1. 概要

このチュートリアルでは、 ArgumentMatcherの使用方法と、ArgumentCaptorとの違いを示します。

Mockitoフレームワークの概要については、この記事を参照してください。

2. Mavenの依存関係

単一のアーティファクトを追加する必要があります。

<dependency>
    <groupId>org.mockito</groupId> 
    <artifactId>mockito-core</artifactId>
    <version>2.21.0</version> 
    <scope>test</scope>
</dependency>

Mockito の最新バージョンは、 MavenCentralにあります。

3. ArgumentMatchers

さまざまな方法でモックメソッドを構成することが可能です。 それらの1つは、固定値を返すことです。

doReturn("Flower").when(flowerService).analyze("poppy");

上記の例では、 String “ Flower”は、analyzeサービスが String“ poppy”を受信した場合にのみ返されます。

しかし、おそらく、より広い範囲の値または事前に不明な値に対応する必要があります。

これらすべてのシナリオで、引数 matchers:を使用してモックメソッドを構成できます。

when(flowerService.analyze(anyString())).thenReturn("Flower");

これで、 anyString 引数マッチャーがあるため、分析に渡す値に関係なく、結果は同じになります。 ArgumentMatchers を使用すると、柔軟な検証またはスタブが可能になります。

メソッドに複数の引数がある場合、一部の引数にのみArgumentMatchersを使用することはできません。  Mockito では、matchersまたは正確な値のいずれかですべての引数を指定する必要があります。

次の例は、これに対する誤ったアプローチです。

abstract class FlowerService {
    public abstract boolean isABigFlower(String name, int petals);
}

FlowerService mock = mock(FlowerService.class);

when(mock.isABigFlower("poppy", anyInt())).thenReturn(true);

これを修正し、 String の名前を「poppy」のままにするために、 eqmatcherを使用します。

when(mock.isABigFlower(eq("poppy"), anyInt())).thenReturn(true);

マッチャーを使用する場合は、さらに2つの注意点があります。

  • それらを戻り値として使用することはできません。呼び出しをスタブする場合は正確な値が必要です
  • 最後に、検証またはスタブ以外で引数マッチャーを使用することはできません

最後のケースでは、 Mockito は誤った引数を検出し、InvalidUseOfMatchersExceptionをスローします。

悪い例は次のとおりです。

String orMatcher = or(eq("poppy"), endsWith("y"));
verify(mock).analyze(orMatcher);

上記のコードを実装する方法は次のとおりです。

verify(mock).analyze(or(eq("poppy"), endsWith("y")));

MockitoAdditionalMatchersも提供し、プリミティブと非プリミティブの両方に一致する ArgumentMatchers で一般的な論理演算(「not」、「and」、「or」)を実装します種類:

verify(mock).analyze(or(eq("poppy"), endsWith("y")));

4. カスタム引数マッチャー

マッチャーを作成すると、特定のシナリオに最適なアプローチを選択し、クリーンで保守可能な最高品質のテストを作成するのに適しています。

たとえば、メッセージを配信するMessageControllerを作成できます。 MessageDTO を受信し、そこからMessageServiceによって配信されるMessageを作成します。

検証は簡単です。MessageService任意のメッセージで1回だけ呼び出したことを確認してください:

verify(messageService, times(1)).deliverMessage(any(Message.class));

メッセージはテスト対象のメソッド内で作成されるため、マッチャーとしてanyを使用する必要があります。

このアプローチでは、 Message 内のデータを検証できません。これは、MessageDTO内のデータとは異なる可能性があります。

そのため、カスタム引数マッチャーを実装します。

public class MessageMatcher implements ArgumentMatcher<Message> {

    private Message left;

    // constructors

    @Override
    public boolean matches(Message right) {
        return left.getFrom().equals(right.getFrom()) &&
          left.getTo().equals(right.getTo()) &&
          left.getText().equals(right.getText()) &&
          right.getDate() != null &&
          right.getId() != null;
    }
}

マッチャーを使用するには、テストを変更し、argThatに置き換える必要があります。

verify(messageService, times(1)).deliverMessage(argThat(new MessageMatcher(message)));

これで、MessageインスタンスにMessageDTOと同じデータが含まれることがわかりました。

5. カスタム引数マッチャーと。  ArgumentCaptor

カスタム引数マッチャーArgumentCaptorの両方の手法を使用して、特定の引数がモックに渡されたことを確認できます。

ただし、 ArgumentCaptorは、検証を完了するために引数値でアサートする必要がある場合、またはカスタム引数マッチャーが再利用されない可能性がある場合に適しています。

ArgumentMatcher を介したカスタム引数マッチャーは、通常、スタブに適しています。

6. 結論

この記事では、 Mockito ArgumentMatcher の機能と、 ArgumentCaptorとの違いについて説明しました。

いつものように、例の完全なソースコードは、GitHubから入手できます。