테스트 더블이란.
테스트의 대상이 의존하는 컴포넌트를 원하는 형태로 동작하는 것처럼 테스트할 수 있도록 하는 방법
액션영화에서 위험한 촬영이 있을 때 스턴트맨이 실제 배우를 대신해 촬영을 진행하곤 한다.
이런 스턴트맨을 외국에서는 '스턴트 더블 (Stunt Double)' 이라 부르는데,
테스트 더블은 테스팅 과정을 촬영에 비유했을 때 비로소 그 의미를 쉽게 유추해볼 수 있다.
테스트 더블(스턴트 더블)이란 실제 객체(배우)로 테스트(촬영)을 진행하기 어려운 경우
대신 진행해주는 방법 및 구성하는 요소들로 정의할 수 있다.
여기서 테스트를 진행하기 어려운 상황이 무엇일까?
단적으로 API를 호출해 데이터를 받아와서 로직을 수행하는 경우, 테스트는 네트워크 연결, 호출하고자 하는 API를 제공하는 서버 상태 등 여러 변수에 따라 테스트하는 환경이 달라질 것이다. 특정 모듈의 내부 구현로직을 검증하는 단위 테스트에서는 항상 같은 조건에서 테스트가 진행되어야 로직 상의 문제가 있는지 확인할 수 있다. 그러나 네트워크 연결상태, 타 서버 등 외부 요소에 종속적으로 진행된다면 테스트의 결과가 로직 이외의 외부 요소에 영향을 받아 테스트 결과가 계속 바뀌어 단위 테스트의 목적을 달성할 수 없을 것이다.
이 때 실제 API 호출을 대신해 API를 호출한 것과 같이 흉내내는 가짜 객체, 테스트 더블 을 도입한다면 테스트 환경을 일정하게 만들어 외부로부터 독립적으로 로직만을 테스트할 수 있다.
Mocks Aren't stubs
Test Double 관련해 마틴 파울러가 쓴 Mocks Aren't Stubs 라는 글은
Test Double 에 대한 정석글...?처럼 많은 개발자들이 받아들이고 있다.
해당 글의 제목에서 유추할 수 있듯, test double 중 mock 과 stub 의 차이 및 test double 의 분류 가이드를 제시한다.
(사실 개인적으로는 그가 초점을 맞춘 것은 mock 과 stub 의 용어보다는
행동검증 / 상태검증 + 정석적인 테스팅 / mock 스타일의 테스팅 등 테스트의 방향성)
그가 말하는 mock 과 stub 의 핵심 차이는,
mock은 행동 검증을 하는 객체로, stub 은 상태 검증을 하는 객체 라는 점인데,
먼저 행동검증과 상태 검증의 차이부터 알아보자.
행동 검증 vs 상태 검증
행동 검증은 의존 컴포넌트의 행동을 검증하는 것으로, 어떤 메소드가 몇 번 호출되었다는 것을 의미한다.
상태 검증은 의존 컴포넌트의 상태(값)을 검증하는 것으로, 특정 메소드가 호출되었을 때 나오는 값을 비교하는 방식이다.
이와 같은 이해를 기반으로 그가 언급한 테스트 더블 분류 가이드는 다음과 같다.
테스트 더블 유형
Dummy
(파라미터 등으로)넘겨지지만 사용되지는 않는 객체.
ex. 메소드의 파라미터 부분을 채우기 위해 사용되는 빈 객체
Fake
동작되도록 구현되어있지만, 프로덕션 환경에서는 적절하지 않은 객체.
단순화된 버전의 동작을 제공한다. ex. in-memory 데이터 베이스, Fake Web Service
Stub
테스트 도중에 호출되면 준비된 결과값을 제공하는 객체.
테스트 시 프로그램 된 것 이외에는 응답하지 않는다. (아무런 동작하지 않음)
테스트 하고자 하는 1가지 상태를 표현
Mock
호출에 대한 기대값을 명세하고, 해당 내용에 따라 동작하도록 프로그래밍 된 객체.
호출 시 동작이 잘 되었는지 확인하는데 사용하는 행위를 검증하기 위한 객체
Spy
실제 객체로도 사용할 수 있고 Stub 객체로도 활용할 수 있으며
필요한 경우 특정 메서드가 제대로 호출되었는지 여부를 확인
임의의 메소드를 stubbing 할 수 있는 실제 객체
Spock 의 Test Double
코드와 함께 보시죠.