외부 요인은 테스트 작성을 어렵게 만들 뿐만 아인라 테스트 결과도 예측할 수 없게 만든다.
Double
영어로 된 테스트 관련 글을 읽으면 test double이란 표현이 자주 나오는데 여기서 double은 본 장에서 설명하는 대역에 해당한다. 즉, test double은 테스트에서 진짜 대신 사용할 대역을 의미한다.
대역의 종류
대역종류 설명
대역종류 | 설명 |
스텁(Stub) | 구현을 단순한 것으로 대체한다. 테스트에 맞게 단순히 원하는 동작을 수행한다. |
가짜(Fake) | 제품에는 적합하지 않지만, 실제 동작하는 구현을 제공한다. DB대신에 메모리를 이용해서 구현한 것과 같다. |
스파이(Spy) | 호출된 내역을 기록한다. 기록한 내용은 테스트 결과를 검증할 때 사용한다. 스텁이기도 하다. |
모의(Mock) | 기대한대로 상호작용하는지 행위를 검증한다. 기대한 대로 동작하지 않으면 익셉션을 발생할 수 있다. 모의 객체는 스텁이자 스파이기도 된다. |
구현 전에 설계해보기
구현전에 모든 기능을 설계하는 것은 불가능하다. 왜냐면 개발을 진행하는 동안에도 요구사항이 계속해서 바뀌기 때문이다. 그럼에도 불구하고 단위 기능을 구현하기에 앞서 어떤 구성 요소가 필요할지 고민하는 것은 의존 대상을 도출할 때 도움이 된다.
상황과 결과 확인을 위한 협업 대상(의존) 도출과 대역 사용
한 테스트는 특정한 상황에서 기능을 실행하고 그 결과를 확인한다. 실제 구현을 이용하면 상황을 만들기 어려울 때가 많다. 제어하기 힘든 외부 상황이 존재하면 다음과 같은 방법으로 의존을 도출하고 이를 대역으로 대신할 수 있다.
- 제어하기 힘든 외부 상황을 별도 타입으로 분리
- 테스트 코드는 별도로 분리한 타입의 대역을 생성
- 생성한 대역을 테스트 대상의 생성자 등을 이용해서 전달
- 대역을 이용해서 상황 구성
대역은 의존하는 대상을 구현하지 않아도 테스트 대상을 완성할 수 있게 만들어주며 이는 대기 시간을 줄여주어 개발 속도를 올리는 데 도움이 된다.
모의 객체를 과하게 사용하지 않기
모의 객체는 스텁과 스파이를 지원하므로 대역으로 모의 객체를 많이 사용한다. 모의 객체를 이용하면 대역 클래스를 만들지 않아도 되니까 처음에는 편할 수 있다. 하지만 결과 값을 확인하는 수단으로 모의 객체를 사용하기 시작하면 결과 검증 코드가 길어지고 복잡해진다. 특히 하나의 테스트를 위해 여러 모의 객체를 사용하기 시작하면 결과 검증 코드의 복잡도는 배로 증가한다. 게다가 모의 객체는 기본적으로 메서드 호출 여부를 검증하는 수단이기 때문에 테스트 대상과 모의 객체 간의 상호 작용이 조금만 바뀌어도 테스트가 깨지기 쉽다.
DAO나 리포지토리와 같이 저장소에 대한 대역은 메모리를 이용한 가짜 구현을 사용하는 것이 테스트 코드 관리에 유리하다.
Reference.