web-dev-qa-db-ja.com

Mockito「文法」の形成

Mockitoは、Javaのためのかなり甘いスタブ/モックフレームワークのようです。唯一の問題は、APIの最適な使用方法に関する具体的なドキュメントが見つからないことです。テストで使用される一般的な方法は次のとおりです。

doXXX(???) : Stubber
when(T) : OngoingStubbing
then(T) : OngoingStubbing
verify(???) : T
given(T) : BDDOngoingStubbing
willXXX(???) : BDDStubber

実際にMockitoの例を見ると、次のようなコードが表示されます。

when(yourMethod()).thenReturn(5);

私が読んだすべてのドキュメントから、上記の例のようにこれらのメソッド呼び出しをデイジーチェーンで連結することで得られたMockitoの「文法」のいくつかの「パターン」を特定しました。私が見つけたいくつかの一般的なパターンは次のとおりです。

When/Then: when(yourMethod())。thenReturn(5);

Given/Will: given(yourMethod())。willThrow(OutOfMemoryException.class);

Do/When: doReturn(7).when(yourMock.fizzBu​​zz());

Will/Given/Do: willReturn(any())。given(yourMethod())。doNothing();

Verify/Do: verify(yourMethod())。doThrow(SomeException.class);

テストケースをモデル化するために、メソッド呼び出しの正しいパターン/組み合わせをどのように選択するかが問題になっています。一見無限のコンボでこれらをデイジーチェーンで接続できるようで、どのパターンがどの問題に適しているのかわかりません。

一部のMockito達人は、Mockitoメソッドのどのパターン/組み合わせがどのタイプのテストケース(およびその理由)に使用されるかについて、いくつかの光を当てるのに役立ちますか?前もって感謝します!

42
IAmYourFaja

Mockitoには多くの場合、いくつかの方法があります。

私は自分が主に使用していることに気づきます:

// Setup expectations
when(object.method()).thenReturn(value);
when(object.method()).thenThrow(exception);
doThrow(exception).when(object.voidMethod());


// verify things
verify(object, times(2)).method();
verify(object, times(1)).voidMethod();

これらの3種類の呼び出しで、必要なものの95%を実行できることがわかりました。

また、使用しているMockitoのバージョンは何ですか? "given"および "will"構成は最新バージョン(1.9.0以降)には存在しません

ただし、戻り値または例外を入力に応答させたい場合があります。この場合、Answerインターフェイスを使用してメソッドの引数を検査し、適切な値を返すことができます。

public class ReturnFirstArg<T> implements Answer<T> {
    public T answer(InvocationOnMock invocation) {
        return invocation.getArguments()[0];
    }
}

when(object.method(7)).thenAnswer(new ReturnFirstArg<Integer>());
16
Matt

when/thenReturnwhen/thenThrowwhen/thenの構文にはいくつかの欠点があります。例えば、

  • when/thenReturnの場合、戻り値の型がワイルドカードを使用したジェネリックであり、同じ型のモックを返したい場合、コンパイル警告を回避することはできません。
  • Voidメソッドにwhen/thenThrowおよびwhen/thenを使用することはできません。
  • Mockitoスパイではこれらの構文を使用できません。
  • モックでwhenを呼び出さない限り、モックオブジェクト、メソッド、引数の組み合わせごとに一度だけresetを呼び出すことができます。
  • 引数マッチャーを使用しているときに、モックオブジェクトとメソッドの1つの組み合わせに対してwhenを複数回呼び出すと、問題が発生する可能性があります。

これらのケースを覚えるのは難しいと思います。したがって、when/thenReturnwhen/thenThrow、およびwhen/then構文がいつ機能するか、または機能しないかを追跡する代わりに、doReturn/whendoThrow/when、およびdoAnswer/whenの代替を優先して、それらを完全に回避することをお勧めします。つまり、doReturn/whendoThrow/whendoAnswer/whenが必要になる場合があり、常にこれらのメソッドを使用できるため、when/thenReturnwhen/thenThrowwhen/thenの使用方法を学習しても意味がありません。

doReturndoThrowdoAnswerは、thenReturnthenThrowthenと同じ方法で連結できます。 doReturndoThrowdoAnswerへの1回の呼び出しで複数の値を返す(またはいくつかの例外をスローする、または複数の応答を実行する)オプションはありません。しかし、これを行う必要はあまりないので、それほど重要ではありません。

doReturnにはもう1つ不利な点があります。 when/thenReturnの場合のように、引数の型のコンパイル時チェックを取得しません。したがって、引数の型が間違っていると、テストを実行するまでわかりません。率直に言って、私は気にしません。

要約すると、私はMockitoを2年以上使用しており、doReturndoThrowdoAnswerの一貫した使用がMockitoのベストプラクティスであると考えています。他のMockitoユーザーは同意しません。

34

実際のところ、思ったよりずっとシンプルに見えます

REF: http://static.javadoc.io/org.mockito/mockito-core/2.7.12/org/mockito/Mockito.html

確認

Mockitoを使用するには、Mockitoの基本的な哲学の1つを理解する必要があります。スタブと検証は分離されています。したがって、あなたが言及した「検証/実行」は実際には「検証」ジョブを実行しているのに対し、他の4つの「文法」はスタブ用です。スタブは、モックオブジェクトがさまざまな状況でどのように反応するかを定義します。検証は、テスト対象システム(SUT)への以前の呼び出しで、モックが期待どおりに呼び出されることを確認することです。

When/Then、Given/Will

それからそれは「いつ」および「与えられた」家族に来ます。単にそれらを互いのエイリアスとして扱うことができます。 "Given"ファミリは、BDDプラクティスに合わせて見えるようにするためにMockito 1.8.xに追加されました。

DoXxx

通常のケースでは、主にwhen(xxx).then(...)(およびgiven(...).will(...))を使用します。ただし、構文が機能しない場合があります。最も明白なケースは、スタブ化されたメソッドの戻り値の型がvoidである場合です。そのような場合、when(mockObj.voidMethod()).thenThrow(anException)はコンパイルされません。回避策として、Do/Whenの代替構文が作成されるため、前の行をdoThrow(anException).when(mockObj.voidMethod())として記述できます

9
Adrian Shum