1. Mock: “완전한 가짜, 기본값만 돌려줌”
개념
- 실제 로직이 전혀 없는 가짜 객체입니다.
- 메서드를 호출해도 기본값(null, 0, false 등)만 반환하고, 아무 일도 안 합니다.
- 테스트에서 “이 메서드가 이렇게 호출됐는지” 같은 행위(호출 여부, 횟수)를 검증할 때 많이 씁니다.
List<String> list = Mockito.mock(List.class);
// 실제로는 리스트에 아무것도 안 들어감
list.add("a");
assertEquals(0, list.size()); // 사이즈는 0 (진짜 add 안 됨)
verify(list).add("a"); // add("a")가 불렸는지만 확인
언제 Mock을 쓰냐?
- 테스트 대상 코드가 의존성(Repository, 외부 API, MessageQueue 등)을 강하게 갖고 있어서 실제로 호출되면 안 될 때.
- “데이터가 어떻게 저장되는지”보다 “이 메서드를 호출했냐/몇 번 했냐”가 중요할 때.
- 예:
UserService를 테스트하면서UserRepository는 완전한 가짜로 두고,save()가 호출됐는지만 보고 싶을 때.
2. Stub: “결과만 고정해 둔 가짜”
개념
- “어떤 입력이 들어오면 이 값을 돌려줘”까지만 필요한 단순 가짜입니다.
- 원래 고전적인 뜻으로는 행위 검증보다, 리턴 값/상태를 만들어내는 용도에 가깝습니다.
- Mockito에서는 별도 타입이 있는 건 아니고,
when(...).thenReturn(...)식의 stubbing 동작 자체를 Stub이라고 많이 부릅니다.
Calculator calculator = Mockito.mock(Calculator.class);
// "1 + 2"를 계산하면 무조건 100을 리턴해라 (이게 Stub 동작)
when(
calculator.add(1, 2)
).thenReturn(
100
);
int result = calculator.add(1, 2); // 항상 100
언제 Stub을 쓰냐?
- 테스트가 “이 메서드에서 이 값이 나와야 다음 단계 테스트가 가능하다”가 핵심일 때.
- 예시:
- 포인트 적립 로직을 테스트하고 싶은데, 외부 포인트 서버에서 항상 “잔액: 1000원”이라고 응답한다고 가정하고 싶을 때.
- 배송비 계산 서비스에서, 주소 검증 서비스가 항상 성공한다고 고정하고 싶을 때.
실무에서는 “Mock 객체에 stubbing을 해서 Stub처럼 쓰는 경우”가 대부분이라, 둘을 엄격히 구분하지 않고 “Mock에 Stub 걸었다” 정도로 표현하는 경우가 많습니다.
3. Spy: “진짜 객체를 감시 + 일부만 가짜로”
개념
- 실제 객체를 감싸는 래퍼입니다.
- 기본적으로는 실제 메서드를 그대로 실행합니다.
- 하지만 특정 메서드만
when(...).thenReturn(...)으로 부분적으로 가짜 동작(부분 mocking)을 줄 수 있습니다. - 즉, “거의 진짜로 돌리되, 몇 개만 살짝 바꾸고 싶다”일 때 사용하는 도구입니다.
List<String> realList = new ArrayList<>();
List<String> spyList = Mockito.spy(realList);
// 부분 stub: size()만 100으로 가짜 설정
when(
spyList.size()
).thenReturn(
100
);
spyList.add("one"); // 실제로 realList에 들어감
spyList.add("two"); // 실제로 realList에 들어감
assertEquals("one", spyList.get(0)); // 진짜 구현 호출
assertEquals(100, spyList.size()); // size()는 가짜 값
verify(spyList).add("one"); // 호출 검증도 가능
언제 Spy를 쓰냐?
- 클래스의 대부분 로직은 그대로 실행하고 싶지만, 일부 메서드는 외부 연동(요금 결제, 외부 API, 파일 I/O)이라 실제로 호출되면 안 될 때.
- 혹은 그 부분만 결과를 강제로 고정하고 싶을 때.
📝 Spy는 편하지만, 진짜 메서드가 실제로 실행되므로 부작용(실제 DB, 네트워크 호출)을 만들 수 있어서 조심해서 써야 합니다.
'Java' 카테고리의 다른 글
| [Java] 입력값 검증의 범위와 책임 (0) | 2026.02.01 |
|---|---|
| [Java] 모니터링 - Prometheus와 Grafana (0) | 2026.02.01 |
| [Java] ORM의 N+1 문제 (0) | 2026.01.13 |
| [Java] @RestController와 HttpMassageConverter (0) | 2026.01.04 |
| [Java] @Controller 와 @RestController (0) | 2025.12.26 |