1. 개요

이 예제에서는 단위 테스트에서 Mockito ArgumentCaptor 를 사용하는 일반적인 사용 사례를 다룰 것  입니다.

또는 다른  Mockito.verify 사용 사례에 대해서는  Mockito Verify Cookbook 을 참조하십시오 .

2. ArgumentCaptor 사용하기

ArgumentCaptor 를 사용하면 검사하기 위해 메서드에 전달된 인수를 캡처할 수 있습니다. 이것은 테스트하려는 메서드 외부의 인수에 액세스할 수 없을 때 특히 유용합니다.

예를 들어  테스트하려는 send 메서드가 있는 EmailService  클래스를 생각해 보십시오.

public class EmailService {

    private DeliveryPlatform platform;

    public EmailService(DeliveryPlatform platform) {
        this.platform = platform;
    }

    public void send(String to, String subject, String body, boolean html) {
        Format format = Format.TEXT_ONLY;
        if (html) {
            format = Format.HTML;
        }
        Email email = new Email(to, subject, body);
        email.setFormat(format);
        platform.deliver(email);
    }

    ...
}

이메일 서비스 에서  . send , platform.deliver  가 새 이메일  을 인수로 취하는 방법에 주목 하십시오. 테스트의 일환으로 새 이메일 의 형식 필드가 Format.HTML  로 설정되어 있는지 확인하고 싶습니다 . 이렇게 하려면 platform.deliver 에 전달된 인수를 캡처하고 검사해야 합니다 .

ArgumentCaptor 를 사용하여 우리를 도울 수 있는 방법을 살펴보겠습니다 .

2.1. 단위 테스트 설정

먼저 단위 테스트 클래스를 생성해 보겠습니다.

@RunWith(MockitoJUnitRunner.class)
public class EmailServiceUnitTest {

    @Mock
    DeliveryPlatform platform;

    @InjectMocks
    EmailService emailService;
  
    ...
}

@Mock 어노테이션을 사용  하여  @InjectMocks 어노테이션 으로 EmailService 에 자동으로 주입되는 DeliveryPlatform 을 모의  합니다. 자세한  내용은 Mockito 어노테이션  문서를 참조하세요.

2.2. ArgumentCaptor 필드 추가

 두 번째로, 캡처된 인수를 저장하기 위해 Email 유형 의 새로운 ArgumentCaptor 필드를 추가해 보겠습니다.

@Captor
ArgumentCaptor<Email> emailCaptor;

2.3. 인수 캡처

셋째, ArgumentCaptor 와 함께  Mockito.verify 를 사용하여 이메일  을 캡처해 보겠습니다 .

Mockito.verify(platform).deliver(emailCaptor.capture());

그런 다음 캡처된 값을 가져와 새  Email 객체로 저장할 수 있습니다.

Email emailCaptorValue = emailCaptor.getValue();

2.4. 캡처된 값 검사

마지막으로 캡처된 Email 객체 를 검사하기 위한 어설션이 있는 전체 테스트를 살펴보겠습니다 .

@Test
public void whenDoesSupportHtml_expectHTMLEmailFormat() {
    String to = "info@baeldung.com";
    String subject = "Using ArgumentCaptor";
    String body = "Hey, let'use ArgumentCaptor";

    emailService.send(to, subject, body, true);

    Mockito.verify(platform).deliver(emailCaptor.capture());
    Email value = emailCaptor.getValue();
    assertThat(value.getFormat()).isEqualTo(Format.HTML);
}

3. 스터빙 피하기

스터빙과 함께 ArgumentCaptor 를 사용할 수  있지만  일반적으로 그렇게 해서는 안 됩니다. 명확히 하자면, Mockito에서 이것은 일반적으로 Mockito.when 과 함께 ArgumentCaptor 를 사용하는 것을 피하는 것을 의미 합니다. 스텁을 사용하면 대신 ArgumentMatcher 를 사용해야 합니다  .

스텁을 피해야 하는 몇 가지 이유를 살펴보겠습니다.

3.1. 테스트 가독성 감소

먼저 간단한 테스트를 고려하십시오.

Credentials credentials = new Credentials("baeldung", "correct_password", "correct_key");
Mockito.when(platform.authenticate(Mockito.eq(credentials)))
  .thenReturn(AuthenticationStatus.AUTHENTICATED);

assertTrue(emailService.authenticatedSuccessfully(credentials));

여기서 Mockito.eq(credentials) 를 사용하여 모의 객체가 언제 객체를 반환해야 하는지 지정합니다.

다음으로 대신 ArgumentCaptor 를 사용하여 동일한 테스트를 고려하십시오 .

Credentials credentials = new Credentials("baeldung", "correct_password", "correct_key");
Mockito.when(platform.authenticate(credentialsCaptor.capture()))
  .thenReturn(AuthenticationStatus.AUTHENTICATED);

assertTrue(emailService.authenticatedSuccessfully(credentials));
assertEquals(credentials, credentialsCaptor.getValue());

첫 번째 테스트와 대조적으로 Mockito.eq(credentials) 와 동일한 작업을 수행하기 위해 마지막 줄에서 추가 assert를 수행해야 하는 방법에 주목하세요 .

마지막으로, credentialsCaptor.capture() 가 무엇을 참조하는지 즉시 명확하지 않다는 점에 주목하십시오   . 가독성을 줄이기 위해 사용하는 라인 외부에 captor를 만들어야 하기 때문입니다.

3.2. 결함  현지화 감소

또 다른 이유는  emailService.authenticatedSuccessfully 가 platform.authenticate 를  호출하지 않으면 예외가 발생하기 때문입니다.

org.mockito.exceptions.base.MockitoException: 
No argument value was captured!

이것은 스텁된 메서드가 인수를 캡처하지 않았기 때문입니다. 그러나 실제 문제는 테스트 자체가 아니라 테스트 중인 실제 방법에 있습니다.

즉, 테스트의 예외로 잘못 안내하는 반면 실제 결함은 테스트 중인 방법에 있습니다.

4. 결론

이 짧은 기사에서는 ArgumentCaptor 사용의 일반적인 사용 사례를 살펴보았습니다 . 또한 스터빙과 함께 ArgumentCaptor 를 사용하지 않는 이유도 살펴보았습니다 .

평소와 같이 모든 코드 샘플은  GitHub에서 사용할 수 있습니다 .

Junit footer banner