1. 序章

Mockito は、人気のあるJavaモックフレームワークです。 これを使用すると、モックオブジェクトの作成モック動作の構成メソッド引数のキャプチャ、およびモックとの相互作用の検証を簡単に行うことができます。

ここでは、モック動作の指定に焦点を当てます。 これを行うには、 when()。thenDoSomething() doSomething()。when()構文の2つの方法があります。

この短いチュートリアルでは、両方がある理由を説明します。

2. when()メソッド

次のEmployeeインターフェイスについて考えてみましょう。

interface Employee {
    String greet();
    void work(DayOfWeek day);
}

テストでは、このインターフェイスのモックを使用します。 文字列“ Hello”を返すようにモックのgreet()メソッドを構成するとします。 Mockitoのwhen()メソッドを使用してこれを行うのは簡単です。

@Test
void givenNonVoidMethod_callingWhen_shouldConfigureBehavior() {
    // given
    when(employee.greet()).thenReturn("Hello");

    // when
    String greeting = employee.greet();

    // then
    assertThat(greeting, is("Hello"));
}

何が起こるのですか? employeeオブジェクトはモックです。 そのメソッドのいずれかを呼び出すと、Mockitoはその呼び出しを登録します。 when()メソッドを呼び出すことで、Mockitoは、この呼び出しがビジネスロジックによる相互作用ではなかったことを認識します。 これは、モックオブジェクトに何らかの動作を割り当てたいというステートメントでした。 その後、thenXxx()メソッドの1つを使用して、期待される動作を指定します。

この時点まで、それは古き良きあざけりです。 同様に、 work()メソッドを構成して、日曜日の引数で呼び出すときに例外をスローするようにします。

@Test
void givenVoidMethod_callingWhen_wontCompile() {
    // given
    when(employee.work(DayOfWeek.SUNDAY)).thenThrow(new IAmOnHolidayException());

    // when
    Executable workCall = () -> employee.work(DayOfWeek.SUNDAY);

    // then
    assertThrows(IAmOnHolidayException.class, workCall);
}

残念ながら、このコードはコンパイルされません。work(employee.work(…))呼び出しでは、work()メソッドの戻り値がvoidであるためです。 したがって、それを別のメソッド呼び出しにラップすることはできません。 voidメソッドをモックできないということですか? もちろん、我々はできます。 doXxx メソッドが救いの手を差し伸べます!

3. doXxx()メソッド

doThrow()メソッドを使用して例外スローを構成する方法を見てみましょう。

@Test
void givenVoidMethod_callingDoThrow_shouldConfigureBehavior() {
    // given
    doThrow(new IAmOnHolidayException()).when(employee).work(DayOfWeek.SUNDAY);

    // when
    Executable workCall = () -> employee.work(DayOfWeek.SUNDAY);

    // then
    assertThrows(IAmOnHolidayException.class, workCall);
}

この構文は前の構文とは少し異なります。voidメソッド呼び出しを別のメソッド呼び出し内にラップしようとはしません。 したがって、このコードはコンパイルされます。

何が起こったのか見てみましょう。 まず、例外をスローしたいと述べました。 次に、when()メソッドを呼び出し、モックオブジェクトを渡しました。 その後、構成するモックインタラクションの動作を指定しました。

これは、以前に使用した when()メソッドとは異なることに注意してください。 また、 when()。の呼び出し後にモックインタラクションを連鎖させたことにも注意してください。一方、は、最初の構文で括弧内に定義しました。

void 呼び出しを構成するなどの一般的なタスクができないのに、なぜ最初の when()。thenXxx()があるのですか? doXxx()。when()構文には複数の利点があります。

まず、開発者にとって、「何らかの相互作用のときに何かを行う」よりも、「何らかの相互作用のときに何かを行う」のようなステートメントを記述および読み取る方が論理的です。

次に、チェーンとの同じ相互作用に複数の動作を追加できます。 それはいつ() クラスのインスタンスを返します OngoingStubbing 、これは thenXxx() メソッドは同じ型を返します。

一方、 doXxx()メソッドは Stubber インスタンスを返し、 Stubber.when(T mock)Tを返します。構成するメソッド呼び出しの種類を指定できます。 ただし、 T はアプリケーションの一部です。たとえば、コードスニペットのEmployeeです。 ただし、 T はMockitoクラスを返さないため、チェーンを使用して複数の動作を追加することはできません。

4. BDDMockito

BDDMockito は、ここで説明した構文とは別の構文を使用します。 非常に簡単です。モック構成では、キーワード「when」を「give 」に、キーワード「do」を「」に置き換える必要があります。 ] will “。 それ以外は、コードは同じです。

@Test
void givenNonVoidMethod_callingGiven_shouldConfigureBehavior() {
    // given
    given(employee.greet()).willReturn("Hello");

    // when
    String greeting = employee.greet();

    // then
    assertThat(greeting, is("Hello"));
}

@Test
void givenVoidMethod_callingWillThrow_shouldConfigureBehavior() {
    // given
    willThrow(new IAmOnHolidayException()).given(employee).work(DayOfWeek.SUNDAY);

    // when
    Executable workCall = () -> employee.work(DayOfWeek.SUNDAY);

    // then
    assertThrows(IAmOnHolidayException.class, workCall);
}

5. 結論

モックオブジェクトをwhen()。thenXxx()または doXxx()。when()の方法で構成することの長所と短所を見てきました。 また、これらの構文がどのように機能するのか、そしてなぜ両方があるのかを見ました。

いつものように、例はGitHubから入手できます。