1. 概要

このチュートリアルでは、単体テストでMockito ArgumentCaptorを使用する一般的な使用例について説明します。

または、他の Mockito.verify のユースケースについては、 Mockito VerificationCookbookを参照してください。

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);
    }

    ...
}

EmailServicesendで、platform.deliverが新しいEmailを引数として取る方法に注目してください。 テストの一環として、新しいEmailのフォーマットフィールドがFormat.HTMLに設定されていることを確認します。 これを行うには、platform.deliverに渡される引数をキャプチャして検査する必要があります。

ArgumentCaptorを使用して支援する方法を見てみましょう。

2.1. 単体テストを設定する

まず、ユニットテストクラスを作成しましょう。

@RunWith(MockitoJUnitRunner.class)
public class EmailServiceUnitTest {

    @Mock
    DeliveryPlatform platform;

    @InjectMocks
    EmailService emailService;
  
    ...
}

@Mockアノテーションを使用してDeliveryPlatformをモックします。これは、@InjectMocksアノテーションとともにEmailServiceに自動的に挿入されます。 詳細については、Mockitoアノテーションの記事を参照してください。

2.2. ArgumentCaptorフィールドを追加します

次に、キャプチャした引数を格納するために、タイプEmailの新しいArgumentCaptorフィールドを追加しましょう。

@Captor
ArgumentCaptor<Email> emailCaptor;

2.3. 議論をキャプチャする

3番目に、Mockito.verifyArgumentCaptorを使用して、Emailをキャプチャします。

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

次に、キャプチャされた値を取得して、新しいEmailオブジェクトとして保存できます。

Email emailCaptorValue = emailCaptor.getValue();

2.4. キャプチャされた値を検査します

最後に、キャプチャされたEmailオブジェクトを検査するためのアサーションを使用したテスト全体を見てみましょう。

@Test
public void whenDoesSupportHtml_expectHTMLEmailFormat() {
    String to = "[email protected]";
    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();
    assertEquals(Format.HTML, value.getFormat());
}

3. スタブの回避

スタブでArgumentCaptorを使用できますが、通常は使用を避ける必要があります。明確にするために、Mockitoでは、これは通常、Mockito.whenArgumentCaptorを使用しないことを意味します。 。 スタブでは、代わりに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)と同じことを行うには、最後の行で追加のアサートを実行する必要があることに注意してください。

最後に、 credentialsCaptor.capture()が何を指しているのかがすぐにはわからないことに注意してください。 これは、使用するラインの外側にキャプターを作成する必要があるためです。これにより、読みやすさが低下します。

3.2。 欠陥の減少ローカリゼーション

もう1つの理由は、emailService.authenticatedSuccessfullyplatform.authenticateを呼び出さない場合、例外が発生することです。

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

これは、スタブメソッドが引数をキャプチャしていないためです。 ただし、実際の問題はテスト自体ではなく、テストしている実際の方法にあります。

言い換えると、はテストの例外に誤って誘導しますが、実際の欠陥はテストしているメソッドにあります。

4. 結論

この短い記事では、ArgumentCaptorを使用する一般的な使用例について説明しました。 また、スタブでArgumentCaptorを使用しない理由についても説明しました。

いつものように、すべてのコードサンプルはGitHubから入手できます。