0Pricing
Java Academy · 강의

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 interaction

InOrder 검증

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 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.

이 강의의 모든 강의

  1. @CsvSource와 @MethodSource를 사용한 매개변수화 테스트
  2. Mockito 고급: 인수 캡처와 스파이
  3. Spring Boot 테스트 슬라이스: @WebMvcTest와 @DataJpaTest
  4. Testcontainers: 실제 데이터베이스 통합 테스트
← Java Academy(으)로 돌아가기