8장. 통합 테스트를 하는 이유
단위 테스트에만 전적으로 의존하면 시스템이 전체적으로 잘 작동하는지 확신할 수 없다
단위 테스트가 비즈니스 로직을 확인하는데 좋지만 비즈니스 로직을 외부와 단절된 상태로 확인하는 것만으로는 충분하지 않다
통합 테스트는 무엇인가?
통합 테스트의 역할
단위 테스트는 세가지 요구사항을 충족하는 테스트다
- 단일 동작 단위를 검증하고
- 빠르게 수행하고
- 다른 테스트와 별도로 처리한다
단위테스트가 아닌 모든 테스트는 통합테스트다
다시 보는 테스트 피라미드
유지비 증가 이유
- 프로세스 외부 의존성 운영이 필요함
- 관련된 협력자가 많아서 테스트가 비대해짐
단위 테스트로 가능한 많이 비즈니스 시나리오의 예외 상황을 확인하고 통합 테스트는 주요 흐름과 단위 테스트가 다루지 못하는 기타 예외 상황을 다룬다
통합 테스트와 빠른 실패
통합 테스트에서 프로세스 외부 의존성과의 상호 작용을 모두 확인하려면 가장 긴 주요 흐름을 선택하라
상호작용을 모두 확인하는 데 필요한 만큼 통합 테스트를 추가로 작성하라
어떤 프로세스 외부 의존성을 직접 테스트해야 하는가
프로세스 외부 의존성의 두 가지 유형
- 관리 의존성
- 테스트에서 제어할 수 있는 의존성
- 데이터베이스
- 비관리 의존성
- 테스트에서 제어할 수 없는 의존성
- SMTP 서버
관리 의존성은 실제 인스턴스를 사용하고 비관리 의존성은 목으로 대체하라
관리 의존성이면서 비관리 의존성인 프로세스 외부 의존성 다루기
프로세스 외부 의존성(데이터 베이스)
데이터 베이스와의 상호작용을 검증하지 말고 데이터베이스의 최종 상태를 확인하라
통합 테스트에서 실제 데이터베이스를 사용할 수 없으면 어떻게 할까?
통합 테스트에서 관리 의존성을 실제 버전으로 사용할 수 없는 경우도 있다
그대로 테스트할 수 없으면 통합 테스트를 아예 작성하지 말고 도메인 모델의 단위 테스트에만 집중하라
의존성 추상화를 위한 인터페이스 사용
인터페이스와 느슨한 결합
인터페이스를 사용하는 이유
- 프로세스 외부 의존성을 추상화해 느슨한 결합을 달성
- 기존 코드를 변경하지 않고 새로운 기능을 추가해 개방 폐쇄 원칙을 달성
위에 2가지 이유 모두 오해
단일 구현을 위한 인터페이스는 추상화가 아니며 해당 인터페이스를 구현하는 구체 클래스보다 결합도가 낮지 않다
진정한 추상화는 발견하는것이지 발명하는것이 아니다
YAGNI 원칙을 위반하는 생각이다
YAGNI 원칙은 현재 필요하지 않는 기능에 시간을 드리지 말라는 원칙이다
- 기회비용
- 프로젝트 코드는 적을수록 좋다
프로세스 외부 의존성에 인터페이스를 사용하는 이유는 무엇인가?
목을 사용하기 위함
인터페이스가 없으면 테스트 대역을 만들수 없음
통합 테스트 모범 사례
통합 테스트를 최대한 활용하는 데 도움이 되는 몇가지 지침
- 도메인 모델 경계 명시하기
- 애플리케이션 내 계층 줄이기
- 순환 의존성 제거하기
도메인 모델 경계 명시하기
항상 도메인 모델을 코드베이스에서 명시적이고 잘알려진 위치에 두도록 하라
도메인 모델에 명시적 경계를 지정하면 코드의 해당 부분을 더 잘 보여주고 더 잘 설명할 수 있다
계층 수 줄이기
대부분의 프로그래머는 간접 계층을 추가해서 코드를 추상화하고 일반화 하려고 한다
추상계층이 너무 많으면 코드베이스를 탐색하기 어렵고 아주 간단한 연산이라 해도 숨은 로직을 이해하기 너무 어려워진다
순환 의존성 제거하기
순환 의존성의 대표적인 예는 콜백이다
순한 의존성은 코드를 읽고 이해할때 알아야 할것들이 너무 많아서 큰 부담이 된다
순한 의존성은 테스트를 방해 한다
테스트에서 다중 실행 구절 사용
통합 테스트에서 두 유스케이스를 모두 확인하려고 할때 아래의 구조가 된다
- 준비
- 실행
- 검증
- 실행
- 검증
이러한 방식은 사용자의 상태가 자연스럽게 흐르기 때문에 설득력이 있고 첫 번째 실행은 두 번째 실행의 준비 단계 역활을 할수 있다
문제는 이러한 테스트가 초점을 잃고 순식간에 너무 커질수 있다
로깅 기능을 테스트하는 방법
- 로깅을 조금이라도 테스트 해야 하는가?
- 만약 그렇다면 어떻게 테스트 해야 하는가?
- 로깅이 얼마나 많으면 충분한가?
- 로거 인스턴스를 어떻게 전달할까?
로깅을 테스트해야 하는가?
로깅은 횡단 기능으로 코드베이스 어느 부분에서나 필요로 할 수 있다
로깅의 종류
- 지원 로깅
- 진단 로깅
로깅을 어떻게 테스트해야 하는가?
목으로 테스트 하지 마라
로깅이 얼마나 많으면 충분한가?
- 과도한 로깅은 코드를 혼란스럽게 한다
- 핵심은 로그의 신호 대비 잡음 비율이다
로거 인스턴스를 어떻게 전달하는가?
- 정적 메서드를 사용하는 것
앰비언트 컨텍스트라고 부른다 이는 안티 패턴이며 다음과 같은 두가지 단점
- 의존성이 숨어 있고 변경하기가 어렵다
- 테스트가 더 어려워진다