Mockitoモックオブジェクトに、次に呼び出されたときに別のオブジェクトを返すように指示するにはどうすればよいですか?


202

だから、私はモックオブジェクトをクラスレベルで静的変数として作成しています...あるテストでFoo.someMethod()は特定の値を返し、別のテストでは別の値を返します。私が抱えている問題は、これを正しく機能させるためにモックを再構築する必要があるようだということです。モックの再構築を避け、各テストで同じオブジェクトを使用するだけです。

class TestClass {

    private static Foo mockFoo;

    @BeforeClass
    public static void setUp() {
        mockFoo = mock(Foo.class);
    }

    @Test
    public void test1() {
        when(mockFoo.someMethod()).thenReturn(0);

        TestObject testObj = new TestObject(mockFoo);

        testObj.bar(); // calls mockFoo.someMethod(), receiving 0 as the value

    }

    @Test
    public void test2() {
        when(mockFoo.someMethod()).thenReturn(1);

        TestObject testObj = new TestObject(mockFoo);

        testObj.bar(); // calls mockFoo.someMethod(), STILL receiving 0 as the value, instead of expected 1.

    }

}

2番目のテストでは、testObj.bar()が呼び出されたときに値として0をまだ受け取っています...これを解決する最良の方法は何ですか?Foo各テストで異なるモックを使用できることはわかっていますが、から複数のリクエストをチェーンmockFooする必要があります。つまり、各テストでチェーンを実行する必要があります。

回答:


43

まず、モックを静的にしないでください。プライベートフィールドにします。setUpクラスを@Beforenotに置くだけ@BeforeClassです。それはたくさん実行されるかもしれませんが、それは安いです。

次に、現在の方法は、モックにテストに応じて異なるものを返す正しい方法です。


438

あなたはまた、可能性スタブ連続通話(#10 API 2.8.9で)。この場合、複数のthenReturn呼び出し、または複数のパラメーター(varargs)を指定した1つのthenReturn呼び出しを使用します。

import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

import org.junit.Before;
import org.junit.Test;

public class TestClass {

    private Foo mockFoo;

    @Before
    public void setup() {
        setupFoo();
    }

    @Test
    public void testFoo() {
        TestObject testObj = new TestObject(mockFoo);

        assertEquals(0, testObj.bar());
        assertEquals(1, testObj.bar());
        assertEquals(-1, testObj.bar());
        assertEquals(-1, testObj.bar());
    }

    private void setupFoo() {
        mockFoo = mock(Foo.class);

        when(mockFoo.someMethod())
            .thenReturn(0)
            .thenReturn(1)
            .thenReturn(-1); //any subsequent call will return -1

        // Or a bit shorter with varargs:
        when(mockFoo.someMethod())
            .thenReturn(0, 1, -1); //any subsequent call will return -1
    }
}

171
.thenReturn()が可変引数を取るという事実を利用することもできるので、コードを次のように短縮できます。when(mockFoo.someMethod())。thenReturn(0、1、-1);
Justin Muller

10
@JustinMuller-これは別の答えの価値があると思います(コメントではなく)
Brian Agnew

16
この場合、この答えは正しいことではありません。このメソッドをスタブして0と1を返す場合、実行してtest1からを実行すれば問題ありませんtest2。ただし、継続的インテグレーション環境がテストを別の順序で実行する可能性があります。またはtest2test1最初に実行せずに単独で実行したい場合もありますが、その場合は失敗します。単体テスト常に互いに独立している必要があります。また、個々のテスト間の依存関係や、テストの特定の順序への依存関係があってはなりません。一方、thenReturnステートメントの連鎖...
Dawood ibnカリーム2015

4
...には、単一thenReturnのにvarargsを使用する場合と同様に、用途があります。これは、この特定のケースでは正しい解決策ではありません。ここでは賛成者の大群が問題を理解できていないようです。
Dawood ibnカリーム2015

2
JUnit自体はテストの順序を保証しません@FixMethodOrder
Roger

29

検索して何かを返し、次に別の呼び出しを行うと例外がスローされます。

    when(mockFoo.someMethod())
            .thenReturn(obj1)
            .thenReturn(obj2)
            .thenThrow(new RuntimeException("Fail"));

または

    when(mockFoo.someMethod())
            .thenReturn(obj1, obj2)
            .thenThrow(new RuntimeException("Fail"));


14

when()メソッドの代わりにspy()とdoReturn()を使用している場合:

異なる呼び出しで異なるオブジェクトを返すために必要なのはこれです:

doReturn(obj1).doReturn(obj2).when(this.spyFoo).someMethod();

クラシックモックの場合:

when(this.mockFoo.someMethod()).thenReturn(obj1, obj2);

または例外がスローされます:

when(mockFoo.someMethod())
        .thenReturn(obj1)
        .thenThrow(new IllegalArgumentException())
        .thenReturn(obj2, obj3);
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.