Mockitoマッチャーは静的メソッドであり、それらのメソッドへの呼び出しです。これらは、およびへの呼び出し中に引数の代わりにwhenなりverifyます。
Hamcrestマッチャー(アーカイブバージョン)(またはHamcrestスタイルのマッチャー)は、オブジェクトがマッチャーの基準に一致した場合にtrueを返すMatcher<T>メソッドmatches(T)を実装および公開する、ステートレスな汎用オブジェクトインスタンスです。それらは副作用がないことを意図しており、一般的に以下のようなアサーションで使用されます。
/* Mockito */ verify(foo).setPowerLevel(gt(9000));
/* Hamcrest */ assertThat(foo.getPowerLevel(), is(greaterThan(9000)));
Mockitoの照合プログラムは、Hamcrestスタイルの照合プログラムとは別に、存在マッチング表現の記述は、メソッド呼び出しに直接収まるように:MockitoマッチャーリターンTHamcrest照合方法はマッチャは、(タイプのオブジェクトを返しますMatcher<T>)。
Mockitoの照合プログラムは、次のような静的メソッドを介して呼び出されるeq、any、gt、及びstartsWithでorg.mockito.Matchersとorg.mockito.AdditionalMatchers。Mockitoバージョン間で変更されたアダプターもあります。
- Mockito 1.xの場合、
Matchers機能の一部の呼び出し(intThatまたはなどargThat)は、パラメータとしてHamcrestマッチャーを直接受け入れるMockitoマッチャーです。ArgumentMatcher<T>拡張org.hamcrest.Matcher<T>内部Hamcrest表現で使用されたされた、Hamcrest整合基本クラスの代わりにMockitoマッチャの任意の並べ替え。
- Mockito 2.0以降では、MockitoはHamcrestに直接依存しなくなりました。
Matchersフレーズとして呼び出されるintThatか、実装されなくなったが同様の方法で使用されるオブジェクトをargThatラップします。およびなどのHamcrestアダプターは引き続き使用できますが、代わりに移動しました。ArgumentMatcher<T>org.hamcrest.Matcher<T>argThatintThatMockitoHamcrest
マッチャーがHamcrestであるか単にHamcrestスタイルであるかに関係なく、それらは次のように適応できます。
/* Mockito matcher intThat adapting Hamcrest-style matcher is(greaterThan(...)) */
verify(foo).setPowerLevel(intThat(is(greaterThan(9000))));
上記のステートメントでfoo.setPowerLevelは、はを受け入れるメソッドですint。is(greaterThan(9000))を返しますがMatcher<Integer>、これはsetPowerLevel引数として機能しません。MockitoマッチャーはintThat、そのHamcrestスタイルのマッチャーをラップし、引数として表示できるintようにを返します。Mockitoマッチャーは、サンプルコードの最初の行のように、式全体を単一の呼び出しにラップします。gt(9000)
マッチャーが行う/返すこと
when(foo.quux(3, 5)).thenReturn(true);
引数マッチャーを使用しない場合、Mockitoは引数の値を記録し、それらのequalsメソッドと比較します。
when(foo.quux(eq(3), eq(5))).thenReturn(true); // same as above
when(foo.quux(anyInt(), gt(5))).thenReturn(true); // this one's different
anyまたはgt(以上)のマッチャーを呼び出すと、Mockitoはマッチャーオブジェクトを格納します。これにより、Mockitoはその等価性チェックをスキップし、選択した一致を適用します。それがargumentCaptor.capture()後の検査のために代わりにその引数を保存するマッチャーを格納している場合。
マッチャーは、ゼロ、空のコレクション、などのダミー値を返しますnull。Mockitoは、0 anyInt()またはfor またはany(Integer.class)empty List<String>for などの安全で適切なダミー値を返そうとしanyListOf(String.class)ます。ただし、型の消去のため、Mockitoにはor 以外の値を返す型情報がありません。そのnullため、プリミティブ値を「自動アンボックス」しようとすると、NullPointerExceptionが発生する可能性があります。any()argThat(...)null
マッチャーはパラメーター値を好みeq、gt取ります。理想的には、これらの値は、スタブ/検証が始まる前に計算する必要があります。別の呼び出しをモックしている最中にモックを呼び出すと、スタブが妨げられる可能性があります。
マッチャーメソッドは戻り値として使用できません。たとえば、Mockito thenReturn(anyInt())などthenReturn(any(Foo.class))でフレーズを使用する方法はありません。Mockitoは、スタブ呼び出しでどのインスタンスを返すかを正確に知る必要があり、任意の戻り値を選択することはありません。
実装の詳細
マッチャーは(Hamcrestスタイルのオブジェクトマッチャーとして)ArgumentMatcherStorageというクラスに含まれるスタックに格納されます。MockitoCoreとMatchersはそれぞれThreadSafeMockingProgressインスタンスを所有しています。このインスタンスには、MockingProgressインスタンスを保持するThreadLocal が静的に含まれています。具体的なArgumentMatcherStorageImplを保持するのは、このMockingProgressImplです。その結果、モックとマッチャーの状態は静的ですが、Mockitoクラスとマッチャークラスの間で一貫してスレッドスコープになります。
ほとんどのマッチャーコールは、のみなどのマッチャための例外を除いて、このスタックに追加しand、orそして、not。これは、メソッドを呼び出す前に引数を左から右に評価するJavaの評価順序に完全に対応しています(依存しています)。
when(foo.quux(anyInt(), and(gt(10), lt(20)))).thenReturn(true);
[6] [5] [1] [4] [2] [3]
この意志:
anyInt()スタックに追加します。
gt(10)スタックに追加します。
lt(20)スタックに追加します。
- 削除
gt(10)しlt(20)て追加しand(gt(10), lt(20))ます。
foo.quux(0, 0)(他の方法でスタブされない限り)デフォルト値を返すCall false。内部的にはMockitoがquux(int, int)最新の通話としてマークします。
- Call
when(false)は、引数を破棄しquux(int, int)、5で識別されたスタブメソッドの準備をします。有効な状態はスタック長が0(等号)または2(マッチャー)の2つだけで、スタックにはマッチャーが2つあります(ステップ1と4)。 Mockito any()は、最初の引数とand(gt(10), lt(20))2番目の引数にマッチャーを使用してメソッドをスタブ化し、スタックをクリアします。
これはいくつかのルールを示しています:
Mockitoは違い言うことができないquux(anyInt(), 0)としますquux(0, anyInt())。どちらもquux(0, 0)、スタックに1つのintマッチャーがある呼び出しのように見えます。したがって、1つのマッチャーを使用する場合は、すべての引数を照合する必要があります。
呼び出し順序は重要なだけでなく、それがすべてを機能させるものです。通常、呼び出し順序が変更されるため、変数へのマッチャーの抽出は機能しません。ただし、メソッドへのマッチャーの抽出はうまく機能します。
int between10And20 = and(gt(10), lt(20));
/* BAD */ when(foo.quux(anyInt(), between10And20)).thenReturn(true);
// Mockito sees the stack as the opposite: and(gt(10), lt(20)), anyInt().
public static int anyIntBetween10And20() { return and(gt(10), lt(20)); }
/* OK */ when(foo.quux(anyInt(), anyIntBetween10And20())).thenReturn(true);
// The helper method calls the matcher methods in the right order.
スタックは頻繁に変更されるため、Mockitoは非常に慎重にポリシングできません。Mockitoまたはモックとやり取りするときにのみスタックをチェックでき、すぐに使用されるか、誤って破棄されるかを知らずにマッチャーを受け入れる必要があります。理論的には、whenまたはへの呼び出し以外ではスタックは常に空である必要がありますverifyが、Mockitoはそれを自動的にチェックできません。で手動で確認できMockito.validateMockitoUsage()ます。
への呼び出しでwhen、Mockitoは実際に問題のメソッドを呼び出します。これは、メソッドをスタブして例外をスローした場合(またはゼロ以外または非null値が必要な場合)に例外をスローします。
doReturnおよびdoAnswer(など)実際のメソッドを呼び出さず、多くの場合、有用な代替手段です。
eqスタブの途中でモックメソッドを呼び出した場合(たとえば、マッチャーの回答を計算するため)、Mockitoは代わりにその呼び出しに対してスタック長をチェックし、失敗する可能性があります。
finalメソッドのスタブ/検証など、何か悪いことをしようとすると、Mockitoは実際のメソッドを呼び出し、追加のマッチャーをスタックに残します。finalメソッドの呼び出しが例外をスローしないかもしれませんが、あなたが得ることがInvalidUseOfMatchersExceptionをモックと浮遊マッチャあなたの次の相互作用から。
一般的な問題
InvalidUseOfMatchersException:
マッチャーをまったく使用する場合は、すべての引数にマッチャーコールが1つだけ含まれていること、およびwhenor verify呼び出しの外部でマッチャーを使用していないことを確認してください。マッチャーは、スタブ化された戻り値またはフィールド/変数として使用しないでください。
マッチャー引数を提供する一環としてモックを呼び出していないことを確認してください。
マッチャーを使用して最終メソッドをスタブ/検証していないことを確認します。これは、マッチャーをスタックに残すのに最適な方法であり、最終メソッドが例外をスローしない限り、これが、モックしているメソッドが最終であることを認識する唯一の場合です。
プリミティブ引数を持つNullPointerException: (Integer) any() nullをany(Integer.class)返し、0 を返します。これは、整数でNullPointerExceptionはintなくを期待している場合に発生する可能性があります。いずれの場合もanyInt()、ゼロを返し、自動ボックス化ステップもスキップするを優先します。
NullPointerExceptionが発生または他の例外:の呼び出しwhen(foo.bar(any())).thenReturn(baz)、実際になります呼び出し foo.bar(null)ますがnull引数を受信した場合に例外をスローするスタブしている可能性があります。への切り替えdoReturn(baz).when(foo).bar(any()) は、スタブ化された動作をスキップします。
一般的なトラブルシューティング
MockitoJUnitRunnerを使用validateMockitoUsageするtearDownか、or @Afterメソッドを明示的に呼び出します(ランナーが自動的に行います)。これは、マッチャーを誤用したかどうかを判断するのに役立ちます。
デバッグの目的validateMockitoUsageで、コードにへの呼び出しを直接追加します。これは、スタックに何かがある場合にスローされます。これは、悪い症状の良い警告です。