Java 如何告诉Mockito mock对象在下次调用时返回不同的内容?

Java 如何告诉Mockito mock对象在下次调用时返回不同的内容?,java,unit-testing,junit,mocking,mockito,Java,Unit Testing,Junit,Mocking,Mockito,所以,我在类级别上创建一个模拟对象作为静态变量,就像这样。。。在一个测试中,我希望Foo.someMethod()返回一个特定的值,而在另一个测试中,我希望它返回一个不同的值。我遇到的问题是,似乎我需要重建模拟,以使其正常工作。我希望避免重建模拟,而只是在每个测试中使用相同的对象 class TestClass { private static Foo mockFoo; @BeforeClass public static void setUp() {

所以,我在类级别上创建一个模拟对象作为静态变量,就像这样。。。在一个测试中,我希望
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.

    }

}

在第二个测试中,当调用testObj.bar()时,我仍然收到0作为值。。。解决这个问题的最佳方法是什么?请注意,我知道我可以在每个测试中使用不同的模拟
Foo
,但是,我必须将多个请求链接到
mockFoo
,这意味着我必须在每个测试中进行链接。

首先不要使模拟成为静态的。让它成为一个私人领域。只需将设置类放在
@之前的
,而不是
@之前的类中。它可能有很多,但很便宜

其次,现在使用的方法是让模拟根据测试返回不同内容的正确方法。

您也可以(2.8.9API中的#10)。在这种情况下,您将使用多个thenReturn调用或一个带有多个参数(varargs)的thenReturn调用


对于使用spy()和doReturn()而不是when()方法的用户:

在不同的调用中,您需要返回不同的对象:

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);

对于所有搜索以返回某个内容,然后搜索另一个调用抛出异常的用户:

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

或者,甚至更干净:

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

我认为您还可以利用.thenReturn()接受varargs这一事实,因此代码可以缩短为:when(mockFoo.someMethod()).thenReturn(0,1,-1)@贾斯汀穆勒-这值得一个单独的答案,我认为(与评论相反)在这种情况下,这个答案是不正确的。如果将此方法存根为返回0和1,那么只要运行
test1
然后运行
test2
,就可以了。但是,您的持续集成环境可能会以其他顺序运行测试。或者,您可能希望自己运行
test2
,而不首先运行
test1
,在这种情况下,它将失败。单元测试必须始终相互独立;而且,各个测试之间不应该存在依赖关系,也不应该存在对特定测试顺序的依赖关系。而链接
然后返回
语句。。。。。。有它的用途,就像对单个
使用varargs然后返回
一样,在这种特殊情况下,它不是正确的解决方案。在我看来,这里的选民群很可能没有理解这个问题。如果没有
@FixMethodOrder
,Junit本身无法确保测试顺序。这应该是答案。
when(mockFoo.someMethod())
        .thenReturn(obj1, obj2)
        .thenThrow(new RuntimeException("Fail"));
when(mockFoo.someMethod()).thenReturn(obj1, obj2);