同じメソッドを同じ引数で複数回呼び出してMockitoを使用する


289

後続の呼び出しでスタブ化されたメソッドが異なるオブジェクトを返す方法はありますか?これを実行して、からの不確定な応答をテストしExecutorCompletionServiceます。つまり、メソッドの戻り順序に関係なくそれをテストするために、結果は一定のままです。

テストしようとしているコードは次のようになります。

// Create an completion service so we can group these tasks together
ExecutorCompletionService<T> completionService =
        new ExecutorCompletionService<T>(service);

// Add all these tasks to the completion service
for (Callable<T> t : ts)
    completionService.submit(request);

// As an when each call finished, add it to the response set.
for (int i = 0; i < calls.size(); i ++) {
    try {
        T t = completionService.take().get();
        // do some stuff that I want to test
    } catch (...) { }        
}

回答:


254

thenAnswerメソッドを使用してそれを行うことができます(でチェーンする場合when):

when(someMock.someMethod()).thenAnswer(new Answer() {
    private int count = 0;

    public Object answer(InvocationOnMock invocation) {
        if (count++ == 1)
            return 1;

        return 2;
    }
});

または、同等の静的doAnswerメソッドを使用します。

doAnswer(new Answer() {
    private int count = 0;

    public Object answer(InvocationOnMock invocation) {
        if (count++ == 1)
            return 1;

        return 2;
    }
}).when(someMock).someMethod();

634

いかがですか

when( method-call ).thenReturn( value1, value2, value3 );

thenReturnの括弧内には、引数がすべて正しいタイプであれば、好きなだけ引数を置くことができます。最初の値はメソッドが最初に呼び出されたときに返され、次に2番目の回答が返されます。他のすべての値がすべて使用されると、最後の値が繰り返し返されます。


4
これはモックでは機能しますが、スパイでは機能しません。元のメソッドを呼び出さないようにする必要がある場合は、doAnswer(...)。when(someSpy).someMethod(...)が必要です。
Yuri

6
@ゆり-かなり。あなたが言及する場合には、あなたはdoAnswerを書く必要はありませんAnswer。そのまま使えますdoReturn(...).when(someSpy).someMethod(...)。エマがスパイよりもモックに興味があると仮定するのは理にかなっているように思われますが、私は私の答えに何かを追加してこれを綴ることができると思います。コメントをありがとう。
Dawood ibnカリーム2014

@DawoodibnKareemを使用すると、最初の呼び出しで値を返し、2番目の呼び出しで例外をスローすることができます。これはどのように行うことができますか?
Rito

@Rito Volodymyrの回答またはRaystormの回答を読んでください。彼らは両方ともそのケースをカバーします。
Dawood ibnカリーム2017

そのような素晴らしい答え。
wild_nothing

151

以前に指摘し、ほぼすべてのコールのチェーン可能です。

だからあなたは呼び出すことができます

when(mock.method()).thenReturn(foo).thenReturn(bar).thenThrow(new Exception("test"));

//OR if you're mocking a void method and/or using spy instead of mock

doReturn(foo).doReturn(bar).doThrow(new Exception("Test").when(mock).method();

Mockitoのドキュメンテーションの詳細情報。


3
非常に役立ちます!mock.methodこの例では、4回目は何が呼び出されたのでしょうか。最初はfooを返しますが、残りはすべてbarを返します。
javaPlease42 2016年

6
モック上の各追加の呼び出しは非常に便利な最後の「thenReturn」や最後の「thenThrow」を返します
フランソワLacoursiere

素晴らしくて簡単な指示をありがとう。今までこれを知りませんでした。2つの同一の呼び出しで2つの異なる結果を返す方法を見つけるのに苦労していました。時間を大幅に節約してください。
CharlesC

68

doReturn()このようにメソッド呼び出しをチェーンすることもできます

doReturn(null).doReturn(anotherInstance).when(mock).method();

かわいいじゃないですか:)


4

MultipleAnswerすべての呼び出しでさまざまな回答をスタブ化するのに役立つクラスを実装しました。ここにコードの一部:

private final class MultipleAnswer<T> implements Answer<T> {

    private final ArrayList<Answer<T>> mAnswers;

    MultipleAnswer(Answer<T>... answer) {
        mAnswers = new ArrayList<>();
        mAnswers.addAll(Arrays.asList(answer));
    }

    @Override
    public T answer(InvocationOnMock invocation) throws Throwable {
        return mAnswers.remove(0).answer(invocation);
    }
}

1
そのオブジェクトを短く、シンプルで読みやすい方法で初期化できますか?
USR-ローカルΕΨΗΕΛΩΝ

1

以下は、異なるメソッド呼び出しで異なる引数を返すための共通メソッドとして使用できます。必要なのは、各呼び出しでオブジェクトを取得する順序で配列を渡すことだけです。

@SafeVarargs
public static <Mock> Answer<Mock> getAnswerForSubsequentCalls(final Mock... mockArr) {
    return new Answer<Mock>() {
       private int count=0, size=mockArr.length;
       public Mock answer(InvocationOnMock invocation) throws throwable {
           Mock mock = null;
           for(; count<size && mock==null; count++){
                mock = mockArr[count];
           }

           return mock;    
       } 
    }
}

getAnswerForSubsequentCalls(mock1, mock3, mock2);最初の呼び出しでmock1オブジェクト、2回目の呼び出しでmock3オブジェクト、3回目の呼び出しでmock2オブジェクトを返します。when(something()).doAnswer(getAnswerForSubsequentCalls(mock1, mock3, mock2)); これは次のように使用する必要がありますwhen(something()).thenReturn(mock1, mock3, mock2);


1

@ [Igor Nikolaev]の8年前の回答に関連して、Java 8で利用可能なラムダ式Answerを使用すると、を使用することで多少簡略化できます。

when(someMock.someMethod()).thenAnswer(invocation -> {
    doStuff();
    return;
});

またはもっと簡単に:

when(someMock.someMethod()).thenAnswer(invocation -> doStuff());

1

BDDスタイル:

import static org.mockito.BDDMockito.*;
...
    @Test
    void submit() {
        given(yourMock.yourMethod()).willReturn(1, 2, 3);

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.