使用Mockito多次调用具有相同参数的相同方法

Emm*_*mma 254 java mocking mockito

有没有办法让stubbed方法在后续调用中返回不同的对象?我想这样做来测试一个非确定的响应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 (...) { }        
}
Run Code Online (Sandbox Code Playgroud)

Daw*_*ica 574

怎么样

when( method-call ).thenReturn( value1, value2, value3 );
Run Code Online (Sandbox Code Playgroud)

您可以在thenReturn的括号中添加任意数量的参数,前提是它们都是正确的类型.第一次调用方法时将返回第一个值,然后是第二个答案,依此类推.所有其他值用完后,将重复返回最后一个值.

  • 这将适用于模拟,但不适用于间谍.如果你需要阻止调用原始方法,你需要doAnswer(...).when(someSpy).someMethod(...). (4认同)
  • @Yuri - 不太好.在你提到的情况下,你不需要`doAnswer`或写一个`Answer`.你可以使用`doReturn(...).when(someSpy).someMethod(...)`.假设Emma对嘲笑而不是间谍感兴趣似乎是合理的,但我想我可以在我的答案中添加一些内容来解释它.感谢您的评论. (4认同)
  • 这是多么光荣的回答啊。 (2认同)

Igo*_*aev 221

您可以使用该thenAnswer方法(链接时when):

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

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

        return 2;
    }
});
Run Code Online (Sandbox Code Playgroud)

或者使用等效的静态doAnswer方法:

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

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

        return 2;
    }
}).when(someMock).someMethod();
Run Code Online (Sandbox Code Playgroud)

  • 当存在需要为回调提供答案的void方法时,这实际上有很大帮助,其中不能使用更简单的`thenReturn(val1,val2,...)`.非常感谢! (8认同)
  • 哦,整洁.文档谈论答案只是为了无效,但这太棒了! (2认同)
  • 作为上述答案的另一个选项,您还可以将doAnswer方法链接在一起.所以`when(someMock.someMethod()).doAnswer(new Answer1()).doAnswer(new Answer2());` (2认同)

Ray*_*orm 131

如前所述,几乎所有的呼叫都是可链接的.

所以你可以打电话

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();
Run Code Online (Sandbox Code Playgroud)

更多信息在Mockito的文件中.

  • 模拟上的每次额外调用都将返回最后一个'thenReturn'或最后一个'thenThrow'非常有用 (6认同)
  • 很有帮助!第四次`mock.method`在这个例子中被调用会发生什么?我想要的东西,第一次返回foo但返回所有其余的吧. (3认同)

Vol*_*bal 65

你甚至可以doReturn()像这样链接方法调用

doReturn(null).doReturn(anotherInstance).when(mock).method();
Run Code Online (Sandbox Code Playgroud)

可爱不是:)


epo*_*pox 19

BDD风格:

import static org.mockito.BDDMockito.given;
        ...

        given(yourMock.yourMethod()).willReturn(1, 2, 3);
Run Code Online (Sandbox Code Playgroud)

经典款式:

import static org.mockito.Mockito.when;
        ...

        when(yourMock.yourMethod()).thenReturn(1, 2, 3);
Run Code Online (Sandbox Code Playgroud)

显式风格:

        ...

        when(yourMock.yourMethod())
            .thenReturn(1)
            .thenReturn(2)
            .thenReturn(3);
Run Code Online (Sandbox Code Playgroud)


小智 5

我已经实现了一个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);
    }
}
Run Code Online (Sandbox Code Playgroud)