399. 목 객체 (Mock Object) 기반 격리 테스트
⚠️ 이 문서는 내 코드(모듈)를 단위 테스트하려는데 외부 데이터베이스, 결제 서버, 네트워크 API 등이 강하게 엮여있어 테스트가 불가능할 때, 그 외부 의존성들을 진짜처럼 흉내 내는 가짜 인형(Mock)으로 싹 갈아치워 100% 완벽한 '격리(Isolation)' 환경을 만들어내는 테스트 기법을 다룹니다.
핵심 인사이트 (3줄 요약)
- 본질: 목(Mock) 객체는 영화 촬영할 때 쓰는 '마네킹'이나 '모형 총'과 같다. 내가 짠 로직(A)이 다른 시스템(B)을 호출할 때, 진짜 B 대신 **"B인 척하면서 내가 미리 설정해 둔 대답만 똑같이 뱉어주는 가짜 인형(Mock B)"**을 꽂아 넣는 기술이다.
- 가치: 외부 DB 서버가 죽어 있거나, 카카오톡 결제 API가 테스트할 때마다 돈이 빠져나가는 문제를 원천 차단하며, 오직 내 코드 내부의
if/else논리 흐름이 맞는지 환경적 변수 없이 초고속으로 검증할 수 있게 해준다.- 기술 체계: 테스트 대역(Test Double) 생태계에 속하며, 더미(Dummy), 스텁(Stub), 스파이(Spy)와 같은 단순 가짜 객체에서 한발 더 나아가 "내 코드가 가짜 객체를 정확히 3번 호출했는가?"라는 **행위(Behavior) 자체를 검증(Verify)**할 수 있는 가장 고도화된 객체다.
Ⅰ. 개요: 엮여있는 코드의 비극 (Context & Necessity)
우리가 쇼핑몰의 결제_진행() 함수를 짰다고 가정해 보자.
public void 결제_진행(Order order) {
if (order.금액 > 0) {
실제_국민은행_서버.결제요청(order); // 🚨 문제의 구간
DB.주문완료_저장(order); // 🚨 문제의 구간
}
}
개발자가 이 코드를 테스트하려고 단위 테스트 버튼을 누른다.
- 비극 1: 테스트를 돌릴 때마다 진짜 내 통장에서 5만 원씩 빠져나간다! (돈 낭비)
- 비극 2: 국민은행 서버가 1시간 동안 점검 중이면 내 코드의 단위 테스트는 전부 뻘건 불(실패)을 띄운다. (내 코드 로직은 완벽한데도 외부 요인에 의해 실패함 = Non-deterministic Test)
- 비극 3: 속도가 미친 듯이 느리다. DB와 네트워크를 탔다 오므로 1번 테스트에 수십 초가 걸린다.
"내 로직(금액 > 0)이 맞는지 확인하고 싶은 거지, 진짜 은행 서버가 잘 돌아가는지 테스트하려는 게 아니잖아!"
이 문제를 해결하기 위해, 진짜 은행 서버 대신 메모리 안에서만 0.001초 만에 "결제 성공!" 이라고 대답해 주는 **가짜 은행 인형(Mock Object)**을 꽂아 넣는 '격리(Isolation)' 기술이 등장했다.
📢 섹션 요약 비유: 우주 비행사가 화성 착륙 훈련(단위 테스트)을 하려고 진짜 화성(실제 DB)까지 날아갈 수는 없습니다. 대신 지구에 화성과 중력이 100% 똑같은 수조 세트장(Mock 객체)을 만들어 놓고, 안전하고 싸고 빠르게 내 우주복(내 코드)의 성능만 떼어서 검사하는 완벽한 훈련 기법입니다.
Ⅱ. Mock 객체의 작동 메커니즘 (행위 검증)
목 객체 프레임워크(Java의 Mockito, Python의 unittest.mock 등)를 쓰면 가짜 인형을 조종하는 마법사가 될 수 있다.
1. 스터빙 (Stubbing) - 가짜 대답 조작하기
개발자는 테스트 코드를 짤 때 목 객체의 뇌(두뇌)를 미리 프로그래밍한다.
- "야, 내 코드가 너한테
결제요청(5만원)쏘면, 무조건True(성공)라고 뻥쳐라." (when().thenReturn()) - 이렇게 하면 내 코드는 진짜 은행 서버와 통신했다고 착각하고 다음
DB.저장()로직으로 부드럽게 넘어간다. 속도는 메모리 접근 수준이므로 빛의 속도다.
2. 검증 (Verify) - 내 코드가 뻘짓 안 했나 감시하기
단순히 가짜 대답만 해주는 것(Stub)을 넘어서, 목 객체는 자기 몸에 남은 터치 기록을 전부 기억한다.
- 테스트가 끝난 후 목 객체에게 묻는다. "방금 내 코드가 너한테
DB.저장()메서드 불렀냐? 혹시 실수로 두 번 부르진 않았냐?" verify(가짜_DB, times(1)).주문완료_저장(order);- 만약 내 코드가 버그가 있어서
저장()을 안 불렀거나 두 번 불렀다면, 목 객체가 고발하여 테스트를 붉은 불(실패)로 만들어 버린다. (행위 기반 검증)
┌─────────────────────────────────────────────────────────────────────────────────┐
│ Mock 객체를 활용한 완벽한 격리 단위 테스트 시각화 │
├─────────────────────────────────────────────────────────────────────────────────┤
│ │
│ ❌ [ 기존 통합 테스트 ] : 느리고 불안정하고 돈 나감 │
│ [ 결제() 로직 ] ──(네트워크 1초)──▶ [ 진짜 K-Bank 서버 ] (점검 중이면 실패) │
│ │
│ 🛡️ [ Mock 객체 주입 격리 테스트 ] : 0.001초만에 100% 성공 보장 │
│ │
│ 1단계 (조작) : Mockito.when(가짜은행.결제요청()).thenReturn("결제성공!"); │
│ │
│ 2단계 (실행) : [ 결제() 로직 ] ──(메모리)──▶ [ 🤡 Mock 가짜은행 인형 ] │
│ (미리 입력된 "결제성공!" 리턴) │
│ │
│ 3단계 (행위검증): Mockito.verify(가짜은행).결제요청_정상적으로_호출했음?(); │
│ (내 if/else 로직이 엉뚱한 길로 안 빠지고 은행 호출 잘했네? 패스!) │
└─────────────────────────────────────────────────────────────────────────────────┘
Ⅲ. 테스트 대역(Test Double)의 4대 천왕
Mock은 가짜 객체(테스트 대역)를 부르는 대명사처럼 쓰이지만, 학문적으로는 역할에 따라 세밀하게 나뉜다.
- Dummy (더미): 로직에 아무 영향도 안 주는데, 깡통 객체가 하나 필요할 때 빈 껍데기만 만들어 던져주는 것.
- Stub (스텁): 무조건 미리 정해둔 긍정/부정의 하드코딩된 결괏값만 수동적으로 리턴하는 바보 인형 (상태 검증용).
- Spy (스파이): 기본적으로 진짜 서버/객체를 호출하되, 호출된 횟수나 파라미터를 몰래 옆에서 감시해서 기록해 두는 스파이.
- Mock (목): 스텁의 기능에 스파이의 감시 기능까지 합쳐져, "행위(Behavior)가 올바르게 일어났는가?"를 직접 Assertion(단언)할 수 있는 완성형 지능 인형.
Ⅳ. 결론
"완벽한 격리(Isolation)만이 순수한 내 로직의 무결성을 증명한다." 현대의 소프트웨어는 결코 혼자 돌아가지 않는다. 마이크로서비스 아키텍처(MSA) 하에서는 함수 하나가 외부 API를 수십 개씩 찌르는 것이 기본이다. 이런 얽히고설킨 의존성 사슬을 칼로 끊어내고, 오직 내가 짠 알고리즘 본연의 책임만을 발가벗겨 시험대에 올리는 기술이 바로 Mocking이다. 물론 너무 Mock을 남용하면 "가짜 세상에서는 완벽했는데 진짜 세상에 합치니까 다 터지더라"는 딜레마(Mockist의 함정)에 빠질 수 있으므로, Mock 기반의 단위 테스트와 진짜 객체를 엮는 통합 테스트(Integration Test)의 균형 잡힌 투 트랙(Two-track) 전략이 반드시 필요하다.
📌 관련 개념 맵
- 전제되는 개념: 단위 테스트 (Unit Test), 제어의 역전(IoC) 및 의존성 주입(DI - 인형을 꽂아 넣기 위함)
- 테스트 대역(Test Double): Dummy, Stub, Spy, Mock, Fake Object
- 대표 프레임워크: Mockito(Java), unittest.mock(Python), Sinon.js/Jest(JavaScript)
- 대척점 기술: 통합 테스트 (Integration Test - 가짜를 쓰지 않고 진짜 DB와 연결해서 테스트)
👶 어린이를 위한 3줄 비유 설명
- 소방관 아저씨들이 불 끄는 연습(단위 테스트)을 하려고, 매일 동네 진짜 집에 불을 지르고(진짜 DB) 끌 수는 없겠죠?
- 그래서 마당에 불이 난 모형 집 세트장(Mock 객체)을 튼튼하게 지어놓고 연습을 합니다! 진짜 집을 태우지 않아도 물 쏘는 연습을 완벽하게 할 수 있어요.
- 게다가 이 모형 집은 "아저씨가 5분 안에 내 창문에 물을 정확히 쐈어!"라고 기록(Verify)까지 해주는 엄청나게 똑똑한 로봇 인형(Mock)이랍니다.