462. Mock (목) - 행위(Behavior) 검증을 위해 예상되는 호출 명세가 프로그래밍된 객체

핵심 인사이트 (3줄 요약)

  1. 본질: 목(Mock) 객체는 스텁(Stub)처럼 가짜 값을 뱉는 것을 넘어, 테스트가 시작되기 전에 "너는 이 A라는 파라미터를 들고 정확히 딱 2번만 불려야 해!"라고 철저하게 행동 대본(Expectation)을 프로그래밍하여 뇌에 주입시켜 놓은 깐깐한 감시관 로봇이다.
  2. 가치: 테스트의 패러다임을 "결과(State)가 뭐야?"에서 **"어떤 절차와 행위(Behavior)를 거쳐서 통신했어?"**로 완전히 전환시킨다. 데이터베이스 저장, 결제 연동, 이메일 발송 등 리턴값이 없는(Void) 파괴적 인프라 통신 구간에서, 내 로직이 엉뚱한 짓을 하지 않고 정확히 1번 찔렀음을 100% 보장하는 무결점 격리 환경을 창조한다.
  3. 융합: 객체 간의 결합도를 제로로 부수어버리는 의존성 주입(DI) 아키텍처 위에서 군림하며, TDD(테스트 주도 개발)의 양대 산맥 중 런던파(London School, Mockist)가 주창한 **"모든 외부 의존성을 완벽한 가짜(Mock)로 찢어발겨라"**라는 극단적이고도 아름다운 소프트웨어 격리 철학의 궁극적 무기다.

Ⅰ. 개요 및 필요성 (Context & Necessity)

  • 개념: Mock(모조품)은 텅 빈 합판으로 만든 가짜 세트장이다. 스텁(Stub)이 "100원을 줘라"는 '상태(State)'에 집착한다면, Mock은 "너 방금 내 배를 찌른 거 맞아? 정확히 찌른 거 확실해?"라며 상호 작용 행위(Behavior) 자체를 검증한다. 개발자가 사전에 입력해 둔 '대본(Expectation)'과 단 1mm라도 다르게 함수가 호출되면, 즉시 빨간불(Fail)을 뿜으며 테스트를 터뜨려버리는 성질 더러운 객체다.

  • 필요성: 내가 회원탈퇴(withdraw) 함수를 짰다. 이 함수 안에서는 DB에서 유저 삭제 -> 카카오톡으로 작별 문자 발송 이라는 2가지 외부 함수가 불린다. 문제는 이 탈퇴 함수가 리턴값이 없다(void). 단위 테스트에서 assertEquals(결과, "탈퇴성공")을 쓸 수가 없다. 그럼 어떻게 탈퇴 로직이 정상 작동했다고 증명할 것인가? 바로 빈자리에 가짜 MockDBMockKakao를 꽂아두고, **"야, 너네 방금 삭제 명령이랑 카톡 발송 명령 정확히 1번씩 받은 거 맞아?"**라고 다그쳐서 "네! 받았습니다!"라는 자백(행위 검증)을 얻어내는 것 말고는 이 우주에 테스트할 방법이 존재하지 않기 때문이다.

  • 💡 비유: Mock은 경찰견 훈련소의 **'폭발물 냄새 묻은 가짜 가방'**과 같습니다. 훈련(테스트)할 때 진짜 폭탄(진짜 DB)을 가방에 넣으면 다 터져 죽습니다. 그래서 가짜 가방(Mock)을 둡니다. 경찰견이 가방을 물어뜯거나(스텁) 결과를 내는 게 중요한 게 아닙니다. 경찰견이 가방 앞에서 **"정확히 짖는 행동(행위 검증)을 딱 3번 했는가?"**라는 대본에 맞는 액션을 취했는지를 훈련 교관(Assert)이 깐깐하게 채점하는 완벽한 행동 통제 시뮬레이션입니다.

  • 등장 배경 및 발전 과정:

    1. 상태 검증의 한계: 전통적 TDD는 무조건 결괏값 5가 나오는지만 비교(AssertEquals)했다. 객체들이 거미줄처럼 통신하는 MSA나 거대 엔터프라이즈 환경에서는, 리턴값 없는 외부 API 호출이 난무하여 검증 불능 상태에 빠졌다.
    2. JMock과 행위 검증의 탄생: 2000년대 초반 "객체는 상태가 아니라 협력(메시지 전송)이다"라는 객체지향의 본질을 깨달은 개발자들이 JMock 프레임워크를 만들며 행위 검증 패러다임을 폭발시켰다.
    3. Mockito의 세계 제패 (현재): 복잡한 대본 설정을 verify()라는 직관적인 단어 하나로 퉁쳐버린 마법의 도구 Mockito가 등장하면서, Mock은 자바 백엔드 생태계에서 숨 쉬듯 쓰이는 '공기'와 같은 존재로 융합되었다.
  • 📢 섹션 요약 비유: Stub이 요리사에게 "소금 10g을 줬다(상태)"라면, Mock은 요리사 뒤에 서 있는 깐깐한 백종원 셰프입니다. 요리가 다 끝나기도 전에 요리사가 설탕을 집어 드는 찰나의 순간, **"에라이! 내가 대본에 소금 1번만 치라 그랬지 설탕 치라 그랬냐!"(행동 일탈 탐지)**라며 즉시 국자를 뺏어 던져버리는(테스트 즉시 실패) 행동 감시자입니다.


Ⅱ. 아키텍처 및 핵심 원리 (Deep Dive)

1. Mock의 동작 아키텍처: 행위 검증(Behavior Verification)의 3단계

Mock 테스팅은 철저하게 '대본(Expect) -> 연기(Act) -> 평가(Verify)'의 아키텍처를 따른다.

[ Mockito를 활용한 행위 검증의 정석 코드 ]

// 1. Arrange (가짜 배우 소환) : 프레임워크가 텅 빈 가짜 로봇(Mock)을 만들어준다.
EmailSender mockEmailSender = mock(EmailSender.class);
OrderService orderService = new OrderService(mockEmailSender); // DI(의존성 주입)

// 2. Act (진짜 로직 실행) : 주인공이 주문을 완료하고, 내부에서 이메일 쏘는 로직을 탄다.
orderService.completeOrder(user, item);

// 3. Assert / Verify (행동 채점) 💥 [Mock의 핵심]
// 결과값이 아니라 행동을 캔다. "야 Mock아, 너 방금 send() 함수 'kim@mail.com' 파라미터 들고 정확히 1번 불린 거 맞아?"
verify(mockEmailSender, times(1)).send("kim@mail.com");

// 만약 orderService 내부에 오타가 나서 send()를 2번 불렀거나, 주소를 엉뚱하게 넘겼다면?
// verify 덫에 걸려 그 즉시 시뻘건 피(Test Fail Error)를 뿜어낸다.
  • 핵심 원리: Mock은 껍데기다. 값을 리턴(return 5)하는 것에 관심이 없다. 오직 "내 배때지에 꽂힌 함수가 몇 번 불렸고, 무슨 파라미터를 물고 들어왔는가"라는 메시지(Message) 송수신의 흔적을 기계적으로 카운팅하고 검사하는 투명한 감시 카메라다.

2. TDD 양대 산맥: 고전파(Detroit) vs 모키스트파(London)

테스트 철학을 가르는 가장 위대한 신학 논쟁이다.

척도고전파 (디트로이트 학파 / Classicist)모키스트파 (런던 학파 / Mockist)
철학"상태 검증(State Verification) 최우선""행위 검증(Behavior Verification) 절대 지지"
Mock 사용극혐함. DB가 필요하면 진짜 DB(또는 Fake 인메모리 DB)를 띄워서 진짜 데이터를 비교해야 직성이 풀림.열광함. 진짜 객체는 무조건 치우고, 나와 연결된 모든 외부 의존성을 Mock으로 싹 다 도배해서 완전히 찢어(Isolation) 놔야 직성이 풀림.
결합도내부 로직을 몰라도 결과만 맞으면 됨 (블랙박스)함수 안에 무슨 함수가 있는지 대본을 짜야 함 (화이트박스, 깨지기 쉬운 테스트 위험)
아키텍트 평가도메인 비즈니스 로직(계산 등) 검증에 최고.외부 인프라 연동(이메일, 카톡, DB 통신) 검증에 최고.
  • 📢 섹션 요약 비유: 고전파는 음식(결과물)을 먹어보고 "음, 짜장면 맛이 완벽하군. 100점!" 하고 통과시킵니다. **모키스트파(Mock)**는 요리사가 춘장을 볶기 시작할 때 1번, 면을 삶을 때 1번, 그릇에 담을 때 1번 레시피(대본)대로 똑같이 행동하는지 손동작 하나하나를 감시해서 "동작이 정확하군. 100점!" 하고 통과시킵니다.

Ⅲ. 융합 비교 및 다각도 분석

1. Mock(목) vs Stub(스텁) vs Spy(스파이) 삼국지 (면접 종결용)

아키텍트는 이 세 가짜 배우를 핀셋처럼 뽑아 써야 한다.

대역 배우근본 속성검증의 포커스에러(Fail)가 언제 터지는가?
Stub (스텁)결괏값 자판기상태 검증 (State)내가 뱉은 값을 받아간 로직이, 맨 마지막에 assertEquals에서 틀릴 때.
Spy (스파이)진짜 객체 + 도청기행위 검증 (Behavior)진짜 로직을 다 태운 후, 마지막에 수첩을 까서 verify로 취조할 때.
Mock (목)엄격한 가짜 대본 로봇행위 검증 (Behavior)함수가 불리자마자 대본(Expectation)과 1글자라도 다르면 즉시 멱살 잡고 터짐.

과목 융합 관점

  • 소프트웨어 공학 (격리와 결합도): "단위 테스트(Unit Test)의 단위(Unit)가 무엇인가?"에 대한 해답이 Mock이다. 만약 A가 B를 부르고 B가 DB를 부를 때 싹 다 묶어서 테스트하면 그건 '통합 테스트(Integration)'다. A 하나만 순수하게 도려내서 수술대(테스트 환경) 위에 올리기 위한 마취제가 바로 Mock이다. 외부와 연결된 모든 혈관(의존성)을 Mock으로 차단(Isolation)해버리면, 이 세상에서 오직 A의 순수한 알고리즘 로직 하나만 빛의 속도로 털어볼 수 있다.

  • 클라우드 / MSA (마이크로서비스): Mock의 철학은 클라우드 MSA 환경에서 **컨슈머 주도 계약 테스트(Consumer Driven Contract Testing)**로 장대하게 융합되었다. 프론트엔드 팀(Consumer)이 백엔드 팀 서버가 만들어지기도 전에, "너희 API 찌르면 이런 JSON 나와야 해"라고 Mock 서버(대본)를 먼저 세팅해 버린다. 백엔드 팀은 이 Mock 대본에 맞춰서 나중에 진짜 서버를 끼워 맞춘다. Mock이 단순한 테스팅을 넘어 조직 간의 협업(API 설계)을 리드하는 아키텍처 중심축이 된 것이다.

  • 📢 섹션 요약 비유: 이 셋의 차이는 학교 시험 감독과 같습니다. Stub은 문제지를 훔쳐서 학생에게 "정답은 3번이야"라고 속삭여주는 나쁜 짝꿍입니다(값 주입). Spy는 학생이 폰을 꺼내 진짜로 커닝하는지 몰래 뒤에서 다 지켜보다가 시험 끝나고 교장 선생님께 고자질하는 카메라입니다. Mock은 아예 학생 손목에 전기 충격기를 달아놓고, 책상이 아닌 곳으로 손이 1cm라도 벗어나는(대본 이탈) 즉시 "찌릿!" 하고 학생을 기절시켜버리는(즉시 Fail) 가장 무자비한 로봇 감독관입니다.


Ⅳ. 실무 적용 및 기술사적 판단

실무 시나리오

  1. 시나리오 — Mock 남용이 부른 끔찍한 리팩토링 지옥 (Fragile Test): TDD 책을 잘못 읽은 주니어 개발자가 주문생성 함수를 짜면서 내부의 자잘한 가격계산 객체, 할인율 객체, 유저등급 객체를 싹 다 Mock으로 떡칠했다. verify(할인율).get(10);, verify(유저).등급(); 등 대본만 100줄을 짰다. 나중에 아키텍트가 성능을 올리려고 내부 함수 호출 순서를 살짝 바꿨다. 결과물(결제 금액)은 똑같이 100원인데, 1,000개의 Mock 테스트 코드가 "대본 순서랑 다르잖아!"라며 일제히 시뻘건 피를 토하며 빌드를 박살 냈다.

    • 아키텍트의 해결책: **구현 세부 사항에 대한 과도한 결합(Over-specified Implementation)**이다. Mock은 독약과 같다. 비즈니스 로직 내부의 자잘한 계산 객체들은 그냥 '진짜 객체(Real)'를 조립해서 쓰거나 값만 뱉는 'Stub'을 써야 한다. Mock은 오직 아키텍처의 맨 끝단, 즉 외부 세상으로 메시지가 튕겨 나가는 통신 구간(이메일 발송, 결제 API 쏘기, DB 저장) 단 하나에만 핀셋으로 박아 넣어야 한다. 내부의 톱니바퀴가 어떻게 도는지를 Mock으로 하나하나 감시하면 그 코드는 평생 리팩토링(구조 변경)을 할 수 없는 콘크리트 화석이 되어버린다.
  2. 시나리오 — Mock이 쳐놓은 거짓말 장막(Illusion of Safety)에 뚫린 라이브 서버: 백엔드 팀이 Mockito를 써서 1만 개의 단위 테스트를 0.5초 만에 통과했다. when(DB).thenReturn("OK")라고 완벽히 대본을 짰다. 오픈 당일 서버가 무너졌다. 진짜 오라클 DB에 날아간 SQL 쿼리의 칼럼 이름에 오타가 나서 SQL 문법 에러가 터진 것이다. 개발자들은 "우리 테스트 100% 다 통과했는데 왜 DB가 죽죠?"라며 어리둥절해했다.

    • 아키텍트의 해결책: Mock과 통합 테스트(Integration Test)의 불균형이 낳은 대참사다. Mock은 "내 로직이 그 함수를 잘 찔렀다"까지만 보장할 뿐, "진짜 찔렀을 때 그쪽 세상(DB)이 똑바로 대답하는가?"는 절대 책임지지 않는 가짜 세상이다. 아키텍트는 "핵심 비즈니스 로직은 Mock으로 빛의 속도로 털되, 외부 인프라(DB)와 닿는 Repository/DAO 껍데기 코드는 절대 Mock을 쓰지 말고 Testcontainers(도커)나 H2 인메모리 DB를 띄워서 진짜로 흙탕물 쿼리를 쏴보는 통합 테스트를 반드시 병행하라"는 테스트 피라미드(Test Pyramid)의 철칙을 수호해야 한다.

도입 체크리스트

  • 조직적: 의존성 주입(DI, Dependency Injection) 아키텍처가 100% 정착되어 있는가? 코드가 KafkaProducer producer = new KafkaProducer(); 라고 단단히 굳어있으면, 밖에서 MockKafka를 쑤셔 넣을 바늘구멍 자체가 존재하지 않는다. 생성자 주입(Constructor Injection)을 스프링(Spring) 팀의 무조건적 표준안으로 강제해야만 Mock이라는 축복이 프로젝트에 내려앉을 수 있다.
  • 기술적: any() 매처(Matcher)를 적절히 섞어 숨통을 트이게 했는가? Mock 대본을 짤 때 verify(email).send("kim@mail.com")처럼 정확한 글자까지 깐깐하게 매칭하면 코드가 너무 피곤해진다. "이메일 주소가 뭐든 간에 어쨌든 전송 함수가 불리긴 했니?" 정도만 확인하고 싶다면, verify(email).send(anyString()) 처럼 유연한 와일드카드 매처를 섞어주어 깨지기 쉬운 테스트(Fragile)를 막아내는 유들유들한 센스가 필요하다.

안티패턴

  • "모든 것을 다 목킹해라 (Mock Everything)": TDD의 런던파(Mockist) 뽕에 잘못 취한 주니어의 안티패턴. 간단한 사칙연산을 하는 유틸리티 클래스나 String, Date 같은 순수 자바 객체까지 죄다 Mock으로 허수아비를 씌워서 "메서드가 불렸는지" 감시한다. 읽기 힘들고, 쓰기 힘들고, 구조만 살짝 고쳐도 연쇄 폭발하는, 테스트 코드가 유지보수 비용의 악성 종양으로 변이하는 최악의 테스팅 범죄다.

  • 📢 섹션 요약 비유: Mock을 과도하게 남발하는 것은, 자전거 페달이 잘 돌아가는지 테스트하려고 **'체인, 톱니바퀴, 바퀴 축'**에 모조리 감시 카메라(Mock)를 50개 달아놓은 미친 짓과 같습니다. 자전거 톱니바퀴 구조를 조금이라도 바꾸면 카메라 50대가 다 부서져 경고음을 냅니다. 진짜 현명한 정비사는 **'뒷바퀴가 굴러가는가?(가장 끝단의 행위 하나)'**에만 카메라를 딱 하나 달아놓고 안쪽의 톱니바퀴들(내부 로직)은 지들끼리 마음대로 돌아가게 내버려 둡니다.


Ⅴ. 기대효과 및 결론

정량/정성 기대효과

구분진짜 통신(DB, API)이 있어야만 테스트가 돌아가는 환경모든 외부 인프라를 Mock으로 잘라내고 껍데기 주입개선 효과
정량외부 통신 지연으로 단위 테스트 1,000개에 10분 소요Mock 주입 후 메모리 안에서만 놀기 때문에 1초 컷 달성지속적 통합(CI) 빌드 및 테스트 속도 99% 극강 가속화
정량결제 API 과금, 외부 서버 점검 등 외부 요인 에러 30%통제된 가상환경 안에서 외부 억울한 실패 원천 차단Flaky Test(오락가락하는 테스트) 소멸로 환경 결함률 0%
정성리턴값이 없는 Void 함수를 검증할 길이 없어 눈으로 찍어봄"정확히 1번 불렸다"는 기계적 증명(Verify)으로 완벽한 확신개발자의 뇌 구조를 '상태'에서 '행위와 메시지 통신'으로 진화시킴

미래 전망

  • AI 오토-모킹(Auto-Mocking)과 대본 생성의 종말: "이 객체 부르면 저거 리턴해라"라고 개발자가 when().thenReturn()을 100줄씩 치던 노가다의 시대가 끝났다. 깃허브 코파일럿(Copilot)과 Cursor AI는 소스코드 내부의 if문 분기점들을 1초 만에 훑고, 이 로직을 다 통과시키려면 어떤 Mock 대본을 짜야 하는지 수백 줄의 Mockito 코드를 완벽한 문법으로 자동 생성해 내는 자동화의 극치를 보여주고 있다.
  • 클라우드 상의 섀도잉 (Shadowing) 테스팅: 단위 테스트 레벨의 Mock(가짜 객체)을 넘어, 앞으로는 진짜 운영(Production) 서버에 날아오는 실제 유저 10만 명의 트래픽을 거울(Shadow)처럼 복사해서, 내 로컬이나 스테이징에 떠 있는 '새로운 버전의 서버'로 꽂아버린다. 가짜 Mock을 짤 필요 없이, 살아 숨 쉬는 진짜 트래픽을 그대로 맞으면서 내 로직의 맷집을 테스트하는 '리얼 타임 인프라 Mocking' 시대로 진화하고 있다.

참고 표준

  • Mockito 프레임워크: 전 세계 자바(Java) 백엔드 개발자 99%가 표준으로 쓰는 압도적 1위의 가짜 로봇 연성 툴. @Mock 딱지 하나로 인터페이스를 허공에서 구현체로 빚어내는 리플렉션과 cglib 흑마법의 결정체.
  • Test Double (테스트 더블): Dummy, Stub, Spy, Mock, Fake 5형제를 묶어 부르는 제라드 메스자로스의 거대한 xUnit 테스팅 패턴 세계관. 그중에서도 대장 격이자 테스팅 패러다임을 바꾼 주인공이 바로 Mock이다.

목(Mock)은 단순한 가짜 객체가 아니라, 아키텍트에게 **"당신의 코드는 세상(외부 의존성)과 어떻게 소통하고 있는가?"**를 심문하는 철학적 잣대다. 코드가 썩어있고 결합도가 스파게티처럼 엉켜있다면 Mock은 당신의 코드에 꽂히는 것을 거부하며 거대한 컴파일 에러를 뿜어낼 것이다. 기술사는 이 무자비한 Mock 프레임워크의 저항을 견뎌내며, 코드를 인터페이스로 자르고 쪼개어 외부의 흙탕물(DB, 네트워크)이 나의 순수한 도메인 로직을 침범하지 못하게 철벽을 세워야 한다. 외부 세상이 모두 멸망해 버린 500 에러의 잿더미 속에서도, 0.001초 만에 묵묵히 내 로직의 완전함을 초록색 불빛(Green)으로 영롱하게 증명해 내는 독야청청한 고립의 성채, 그것이 Mock이 쌓아 올린 TDD 클린 아키텍처의 진정한 아름다움이다.

  • 📢 섹션 요약 비유: Mock 테스트는 비행기 엔진을 테스트하기 위한 완벽한 **'진공 풍동 실험장(Wind Tunnel)'**입니다. 하늘에 진짜 비행기를 띄워(통합 테스트) 엔진을 테스트하면 새가 날아와서, 혹은 번개가 쳐서(외부 환경 요인) 엔진이 고장 났는지 구분이 안 갑니다. 진짜 세상(DB, API)을 완전히 차단하고(Mock), 기계로 내가 만든 일정한 바람(통제된 행위)만 정확히 쏴주면서 오직 엔진의 순수한 돌아가는 모습(로직 행위)만을 100%의 진실로 측정해 내는 궁극의 실험실입니다.

📌 관련 개념 맵 (Knowledge Graph)

개념 명칭관계 및 시너지 설명
스텁 (Stub) & 스파이 (Spy)스텁이 "값"만 주는 멍청한 자판기, 스파이가 "기록"만 살짝 빼돌리는 위장 요원이라면, Mock은 대본과 다르면 총을 쏴버리는 가장 엄격하고 극단적인 무결점 통제관이다. (이전 장 460, 461번)
의존성 주입 (DI)Mock이라는 가짜 심장을 진짜 로봇의 배를 갈라 꽂아 넣으려면, 아키텍처가 "무조건 밖에서 주입받는다(DI)"는 조립식 구조로 설계되어 있어야만 한다. Mock의 필수 전제 조건.
상태 검증 vs 행위 검증"정답 5가 나왔나(상태 검증, AssertEquals)"의 시대를 끝내고, "정답은 모르겠고, 5를 만들기 위해 DB 찌르는 함수를 정확히 2번 호출했는가(행위 검증, Verify)"로 패러다임을 바꾼 사상.
인터페이스 분리 원칙 (ISP)뚱뚱한 콘크리트 클래스(오라클 DB)를 쓰면 Mock을 씌우기 무겁고 버그가 난다. 얇고 예쁜 껍데기(Interface)로 뽑아내야 프레임워크가 가벼운 가짜를 1초 만에 찍어내어 덮어씌울 수 있다.
단위 테스트 (Unit Test)단위 테스트가 "진정한 의미의 단위(격리)"가 될 수 있도록 외부 세상의 모든 끈을 가위로 잘라버리고 그 빈자리에 가짜 접착제(Mock)를 발라 출혈을 막아주는 일등 공신.

👶 어린이를 위한 3줄 비유 설명

  1. 내가 '강아지 밥 주기 기계'를 만들었는데, 진짜 강아지한테 밥을 주며 테스트하려니까 너무 배부르게 먹일까 봐 걱정됐어요.
  2. 그래서 **'진짜처럼 짖지만 아무것도 안 먹는 가짜 로봇 강아지'**를 갖다 놓고, 내가 밥을 줄 때마다 로봇 강아지가 정확히 "멍!" 하고 한 번씩 짖는지 감시하기로 했어요.
  3. 이렇게 진짜 친구 대신에 놔두고, 내가 정해준 규칙(대본)대로 똑바로 부르지 않으면 "삑! 틀렸어!"라고 화를 내는 무서운 가짜 로봇 선생님을 **'목(Mock)'**이라고 부른답니다!