06 단위테스트 스타일
단위테스트의 세가지 스타일
출력기반 테스트
: SUT에 입력을 넣고 생성되는 출력을 점검 = 함수형
- 부작용이 없는 코드 선호를 강조하는 프로그래밍 방식인 함수형 프로그래밍에 뿌리를 두고있다.
상태기반 테스트
: 작업이 완료된 후 시스템 상태를 확인하는것 (외부 의존성의 상태, DB, FileSystem ,sut의 상태)
통신기반 테스트
: mock을 사용하여 SUT와 협력자간의 통신을 검증.
스타일 비교
| - | 출력기반|상태기반|통신기반| |–|–|–|–| |리팩터링 내성을 지키기 위한 노력| 낮음|중간|중간| |유지비|낮음|중간|높음|
- 항상 다른것보다 출력기반 테스트를 선호하라.
함수형 아키텍처 이해
- 수학적 함수를 사용한 프로그래밍, 숨은 입출력이 없다.
- 수학적 함수 = 메서드 명, 인수, 반환타입으로 구성된 메서드 시그니처에 명시된다.
- 호출 횟수에 상관없이 주어진 입력에 동일한 출력을 생성해야한다.
숨은 입출력
- 부작용 : 메서드 시그니처에 표시되지않는 출력, 상태변경 혹은 파일업데이트를 하는 부작용이 발생.
- 예외 : 예외를 던지면 시그니처에 설정된 계약을 우회하는 경로를 만든다. 어디서든 발생할수있으므로 메서드 시그니처가 전달하지않는 출력을 추가한다.
- 내외부 상태에 대한 참조 : DB에서 데이터 질의, 정적속성을 노출시키는 메서드, 변경가능 필드 참조 등 메서드 시그니처에 없는 실행흐름에 대한 입력.
함수형 아키텍처란
부작용을 완전 제거하는것이 아니라, 비즈니스로직을 처리하는 코드와 부작용을 일으키는 코드를 분리하는것.
- 결정을 내리는 코드 (함수형 코더) : 부작용이 필요없고, 수학적 함수로 작성 가능.
- 결정에 따라 작용하는 코드 (가변 셸): 수학적 함수로 나온 결정을 db변경이나 메시지와같이 가시적인 부분으로 변환한다.
- 객체지향 프로그래밍은 작동부분을 캡슐화해 코드를 이해할수있게 하고, 함수형 프로그래밍은 작동 부분을 최소화해 코드를 이해할 수 있게 한다.
함수형 아키텍처와 육각형 아키텍처 비교
- 육각형 아키텍처는 도메인계층과 애플리케이션 계층을 구별한다 = 결정과 실행을 분리한다.
- 의존성간의 단방향 흐름, 도메인계층은 애플리케이션 계층에 의존할 수 없다.
- 함수형 아키텍처의 모든 부작용은 셸이 처리하지만, 육각형 아키텍처는 계층의 경계를 넘지않는 한 부작용은 괜찮다.
- 함수형 아키텍처는 육각형 아키텍처의 하위 집합이다.
함수형 아키텍처와 출력 기반 테스트로의 전환
- 테스트를 파일시스템에서 분리하기위한 mock 사용
- 함수형 아키텍처로 리팩터링하기
- ASIS : 매서드 내에서 결정, 파일 업데이트까지 수행
- TOBE : 메서드 내에서 FileUpdate라는 (명령) 객체 반환, 가변셸에서 FileUpdate를받아 업데이트 수행. 코어와 셸 사이 연결부는 service 가 수행.
함수형 아키텍처의 단점
- 성능 단점
- 출력기반 테스트는 mock을 사용하지않고도 빠르지만, 그로인해 외부 의존성을 더 많이호출하고 성능이 떨어진다.(?)
- 성능 : 외부 의존성에 대한 호출 수
- 출력기반 테스트는 mock을 사용하지않고도 빠르지만, 그로인해 외부 의존성을 더 많이호출하고 성능이 떨어진다.(?)
- 코드 베이스 크기 증가
- 궁극적으로는 코드 복잡도가 낮아지고 유지보수성이 향상되지만, 초기엔 코드가 더 필요하다.