Mockito 고급: 인수 캡처와 스파이
ArgumentCaptor로 메서드 인수를 캡처하고 Mockito.spy로 실제 객체를 부분적으로 모의 처리합니다.
Mockito 고급: 인수 캡처와 스파이은(는) CoddyKit의 무료 Java Academy 강의입니다. 이것은 4개 중 2번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 Java Academy 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. Java Academy 강의에는 총 4개의 강의가 포함되어 있습니다.
ArgumentCaptor: 메서드 인수 캡처
ArgumentCaptor는 모의 메서드에 전달된 인수를 캡처하므로 해당 인수를 검증할 수 있습니다. 테스트 대상 시스템 내부에서 인수가 생성되어 직접 접근할 수 없을 때 유용합니다.
ArgumentCaptor 생성 및 사용
인수 유형에 맞는 캡처러를 만들고, verify()에서 인수 매처로 captor.capture()를 전달한 다음 captor.getValue()를 호출하여 캡처된 인수를 가져옵니다.
@Test
void sends_correct_email() {
ArgumentCaptor<EmailMessage> captor = ArgumentCaptor.forClass(EmailMessage.class);
userService.register(new CreateUserRequest("alice@example.com"));
verify(emailService).send(captor.capture());
EmailMessage msg = captor.getValue();
assertEquals("alice@example.com", msg.getTo());
assertTrue(msg.getSubject().contains("Welcome"));
}@Captor 어노테이션
@ExtendWith(MockitoExtension.class)와 함께 @Captor를 사용하면 장황한 ArgumentCaptor.forClass() 호출을 피할 수 있습니다.
@ExtendWith(MockitoExtension.class)
class UserServiceTest {
@Mock EmailService emailService;
@Captor ArgumentCaptor<EmailMessage> emailCaptor;
@Test
void captures_email() {
// ...
verify(emailService).send(emailCaptor.capture());
assertEquals("Welcome!", emailCaptor.getValue().getSubject());
}
}여러 호출 캡처
메서드가 여러 번 호출될 때는 captor.getAllValues()를 사용합니다. 호출 순서대로 캡처된 모든 값의 목록을 반환합니다.
verify(emailService, times(3)).send(emailCaptor.capture());
List<EmailMessage> messages = emailCaptor.getAllValues();
assertEquals(3, messages.size());
assertEquals("Confirmation", messages.get(0).getSubject());Mockito 스파이: 부분 모의 처리
Mockito.spy()는 실제 객체를 감쌉니다. 명시적으로 스텁 처리하지 않는 한 모든 메서드는 정상적으로 동작합니다. 테스트하기 어려운 의존성이 일부 있지만 대부분 정상적으로 동작하는 클래스를 테스트할 때 사용합니다.
List<String> realList = new ArrayList<>();
List<String> spy = Mockito.spy(realList);
spy.add("hello"); // calls real ArrayList.add()
System.out.println(spy.size()); // 1 — real method called
doReturn(42).when(spy).size(); // stub just size()
System.out.println(spy.size()); // 42 — stubbed@Spy 어노테이션
@ExtendWith(MockitoExtension.class)와 함께 @Spy를 사용하여 스파이를 만듭니다. 필드는 인라인으로 초기화하거나 @Spy UserService svc = new UserService(repo);처럼 초기화해야 합니다.
@ExtendWith(MockitoExtension.class)
class OrderServiceTest {
@Spy
OrderService orderService = new OrderService(mockRepo, mockEmail);
}@SpyBean으로 Spring 빈 감시
Spring Boot 테스트에서 @SpyBean은 기존 Spring 빈을 Mockito 스파이로 감쌉니다. 스텁 처리하지 않으면 실제 동작을 수행합니다. @SpringBootTest와 함께 사용합니다.
@SpringBootTest
class IntegrationTest {
@SpyBean EmailService emailService;
@Test
void order_sends_email() {
orderService.placeOrder(cart);
verify(emailService).sendConfirmation(any());
}
}스파이에서 doReturn과 when().thenReturn() 비교
스파이에는 when(spy.method()).thenReturn(value) 대신 doReturn(value).when(spy).method()을 사용합니다. when(spy.method()) 형식은 실제 메서드를 호출하므로 부작용이 발생할 수 있습니다.
// Correct for spies:
doReturn(List.of()).when(spy).findAll();
// WRONG for spies — calls real findAll() first:
when(spy.findAll()).thenReturn(List.of()); // real method called!상호 작용이 없었는지 검증
verifyNoInteractions(mock)을 사용하여 모의 객체가 한 번도 호출되지 않았는지 검증하고, 예상된 모든 호출 이후 verifyNoMoreInteractions(mock)을 사용하여 예상하지 못한 호출을 찾습니다.
verifyNoInteractions(emailService); // never called
verify(repo).save(any());
verifyNoMoreInteractions(repo); // save() was the only interactionInOrder 검증
InOrder를 사용하여 모의 메서드가 특정 순서로 호출되었는지 검증합니다.
InOrder inOrder = inOrder(repo, emailService);
inOrder.verify(repo).save(any());
inOrder.verify(emailService).send(any()); // save happened BEFORE send인수 매처
캡처러를 매처와 결합합니다: any(), eq(), anyString(), argThat(predicate). 인수 중 하나라도 매처를 사용하면 모두 매처를 사용해야 합니다.
verify(repo).save(argThat(user ->
user.getEmail().endsWith("@example.com") &&
user.getStatus() == UserStatus.ACTIVE));빠른 확인
스파이를 스텁 처리할 때 when().thenReturn() 대신 doReturn을 사용하는 이유는 무엇인가요?
복습
ArgumentCaptor는 호출 후 검증할 수 있도록 인수를 캡처합니다. 스파이는 실제 객체를 감싸며 스텁 처리하지 않는 한 실제 객체에 작업을 위임합니다. 스파이에는 doReturn을 사용합니다. Spring 통합 테스트에는 @SpyBean을 사용합니다. InOrder로 호출 순서를 검증합니다.
자주 묻는 질문
“Mockito 고급: 인수 캡처와 스파이” 강의는 무료인가요?
네 — “Mockito 고급: 인수 캡처와 스파이” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 Java Academy 강의 전체를 잠금 해제할 수 있습니다. Java Academy 강의에는 총 4개의 강의가 포함되어 있습니다.
“Mockito 고급: 인수 캡처와 스파이”에서 뭘 배우나요?
ArgumentCaptor로 메서드 인수를 캡처하고 Mockito.spy로 실제 객체를 부분적으로 모의 처리합니다. 브라우저에서 직접 실행하는 실습 코드로 Java Academy을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.
Java Academy을(를) 시작하는 데 경험이 필요한가요?
사전 경험은 필요하지 않습니다. CoddyKit의 Java Academy은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 2번째 강의입니다.
“Mockito 고급: 인수 캡처와 스파이” 강의는 얼마나 걸리나요?
대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.
이 Java Academy 강의에서 코드를 작성하고 실행할 수 있나요?
네. 모든 Java Academy 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.
이 강의의 모든 강의
- @CsvSource와 @MethodSource를 사용한 매개변수화 테스트
- Mockito 고급: 인수 캡처와 스파이
- Spring Boot 테스트 슬라이스: @WebMvcTest와 @DataJpaTest
- Testcontainers: 실제 데이터베이스 통합 테스트