Mock, Stub, Spy 테스트 더블 설계 가이드
실무에서 중요한 것은 용어를 외우는 것이 아니라, 왜 이 경계를 대체해야 하는가를 설명할 수 있는지입니다.
테스트 더블의 목적은 불확실성 통제입니다
테스트 더블을 도입하는 주된 이유는 다음과 같은 의존성을 고립하기 위해서입니다.
- 느리다
- 비결정적이다
- 비싸다
- 현재 단위 밖의 외부 경계다
대표 예시는 다음과 같습니다.
- 이메일 게이트웨이
- 결제 클라이언트
- 파일 시스템
- 시간
- 랜덤 값 생성기
반대로 의존성이 이미 단순하고 메모리 안에서 빠르게 동작한다면, 굳이 대체하는 것이 신뢰도를 낮출 수도 있습니다.
Stub은 입력을 통제할 때 유용합니다
Stub은 테스트 대상이 결정적인 입력을 받도록 만들고 싶을 때 적합합니다.
예를 들면:
- 사용자 저장소가 미리 정의한 사용자를 반환
- 환율 API가 고정된 환율을 반환
- clock이 고정 시점을 반환
핵심은 상호작용을 검증하는 것이 아니라, 예측 가능한 입력을 제공하는 것입니다.
Mock는 정말 중요한 상호작용 계약을 검증할 때 써야 합니다
Mock는 호출 그 자체가 의미가 있을 때 가장 강합니다.
예를 들면:
- 회원 가입 성공 후 이메일이 발송되어야 한다
- 결제 게이트웨이가 정확한 요청으로 한 번 호출되어야 한다
- 권한 있는 작업 후 감사 이벤트가 발행되어야 한다
여기서 중요한 단어는 “정말 중요한”입니다. 모든 내부 호출을 계약처럼 검증하면 테스트는 금방 brittle해집니다.
Spy는 더 높은 현실성을 유지하며 관찰할 때 좋습니다
Spy는 원래 동작을 더 많이 유지한 상태에서, 특정 호출 여부나 인자를 관찰하고 싶을 때 유용합니다.
특히 다음 상황에 잘 맞습니다.
- 의존성 자체는 대부분 그대로 써도 된다
- 사용 여부만 관찰하면 충분하다
- 전체를 mock로 바꾸는 것이 과하다
잘 쓰면 spy는 full mock보다 더 현실적인 테스트를 유지할 수 있습니다.
상태 검증이 상호작용 검증보다 더 강한 경우가 많습니다
많은 팀이 상호작용 검증이 더 정밀해 보인다는 이유로 mock를 과하게 씁니다. 하지만 실전에서는 상태 검증이 더 튼튼한 경우가 많습니다.
강한 예:
- 회원 가입 후 사용자 레코드가 활성 상태로 저장된다
약한 예:
- repository method A가 한 번, method B가 한 번 호출된다
결과 상태나 외부에서 관찰 가능한 결과를 검증하는 테스트는 대체로 리팩터링에 더 오래 버팁니다.
과도한 mocking은 거짓 자신감을 만듭니다
mock가 너무 많아지면 실제 시스템 경계가 어긋나도 테스트는 여전히 통과하는 경우가 많습니다.
특히 다음 패턴을 경계해야 합니다.
- 모든 의존성을 기본적으로 mock 처리
- 대부분의 assertion이 call count 검증
- stubbed 데이터가 실제 계약과 멀어짐
- 실제 버그보다 내부 리팩터링에 더 자주 깨짐
이런 신호는 테스트가 행동의 가치보다 구현의 모양을 증명하고 있다는 뜻입니다.
Fake는 생각보다 강력한 선택지입니다
실무에서는 mock보다 fake가 더 나은 경우도 많습니다.
예를 들면:
- in-memory repository
- fake message bus
- 임시 파일 저장소
fake는 빠르고 제어 가능하면서도 실제 동작에 더 가까운 경우가 많아, 속도와 신뢰의 균형을 더 잘 만들어줍니다.
무엇을 선택할지에 대한 실전 기준
간단히 정리하면:
- 알려진 입력이 필요하면 stub
- 상호작용 자체를 증명해야 하면 mock
- 관찰만 필요하고 현실성을 더 유지하고 싶으면 spy
- 가벼운 대체 구현이 더 신뢰를 주면 fake
이 선택은 항상 “이 테스트가 가장 먼저 잡아야 할 결함은 무엇인가”에서 출발해야 합니다.
리뷰 체크리스트
테스트 더블이 많은 설계를 볼 때는 최소한 다음을 물어야 합니다.
- 왜 이 의존성을 대체하는가
- 이 테스트는 행동을 검증하는가, 구현 구조를 검증하는가
- mock보다 stub나 fake가 더 단순하지 않은가
- 내부 리팩터링 후에도 이 테스트가 가치 있는가
- 상호작용 검증이 정말 중요한 프로토콜 행동에만 쓰였는가
마무리
Mock, Stub, Spy는 역할이 분명할수록 더 유용합니다. 좋은 테스트는 더블을 많이 쓰는 테스트가 아니라, 어떤 경계를 왜 통제하는지 설명할 수 있는 테스트입니다.
Continue Reading
다음으로 읽기 좋은 글
React Testing Library 실전 설계 가이드
React Testing Library를 사용자 중심 테스트 도구로 활용하는 방법을 정리합니다. query 우선순위, 상호작용 테스트, 비동기 UI, provider wrapper, 과도한 mocking 회피까지 실무 기준으로 다룹니다.
🧪 TestTDD 실천 가이드: Red-Green-Refactor
TDD를 순서 암기가 아니라 설계 피드백 루프로 보고, Red-Green-Refactor의 의미, 잘 맞는 문제와 과한 문제, 팀에서 지속 가능하게 적용하는 방법을 정리합니다.
🔧 ToolsPostman 실전 가이드: API 테스트, 자동화, 협업
Postman을 API 탐색 도구에서 끝내지 않고, 환경 관리, 컬렉션 구조, 공유 테스트 흐름, Newman 기반 CI 검증까지 실무적으로 사용하는 방법을 정리합니다.
⚙️ BackendSpring Boot 테스트 전략 가이드
단위 테스트, 슬라이스 테스트, 통합 테스트를 어떻게 배치해야 하는지와 함께, 빠른 피드백과 높은 신뢰도를 동시에 얻는 실전 전략을 정리합니다.
다음 탐색