是否有一种方法可以让存根方法在后续调用时返回不同的对象?我希望这样做是为了测试来自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 (...) { }        
}

当前回答

BDD风格:

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

        given(yourMock.yourMethod()).willReturn(1, 2, 3);

经典的风格:

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

        when(yourMock.yourMethod()).thenReturn(1, 2, 3);

明确的风格:

        ...

        when(yourMock.yourMethod())
            .thenReturn(1)
            .thenReturn(2)
            .thenReturn(3);

取决于参数

假设我们有2个参数,检查第2个(列表)参数的大小:

        ...

        when(yourMock.yourMethod(any(), anyList()))
             .thenAnswer(args -> ((List) args.getArgument(1)).size() < 2
                                 ? 1
                                 : 3);

arg是对象,所以我们必须将arg转换为我们的类型。在我的例子中,我转换了^^^ to (List)。

BDD

        ...

        given(yourMock.yourMethod(any(), anyList()))
             .willAnswer(args -> ((List) args.getArgument(1)).size() < 2
                                 ? 1
                                 : 3);

其他回答

几乎所有的调用都是可链的:

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

你可以使用LinkedList和Answer。如

MyService mock = mock(MyService.class);
LinkedList<String> results = new LinkedList<>(List.of("A", "B", "C"));
when(mock.doSomething(any())).thenAnswer(invocation -> results.removeFirst());

Following可以用作一个通用方法,在不同的方法调用上返回不同的参数。我们需要做的唯一一件事是,我们需要传递一个数组,其中对象应该在每次调用中检索。

@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对象,第二次调用时返回mock3对象,第三次调用时返回mock2对象。 应该像(something())那样使用。doAnswer(getAnswerForSubsequentCalls(mock1, mock3, mock2)); 这几乎类似于when(something())。然后返回(mock1, mock3, mock2);

BDD风格:

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

        given(yourMock.yourMethod()).willReturn(1, 2, 3);

经典的风格:

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

        when(yourMock.yourMethod()).thenReturn(1, 2, 3);

明确的风格:

        ...

        when(yourMock.yourMethod())
            .thenReturn(1)
            .thenReturn(2)
            .thenReturn(3);

取决于参数

假设我们有2个参数,检查第2个(列表)参数的大小:

        ...

        when(yourMock.yourMethod(any(), anyList()))
             .thenAnswer(args -> ((List) args.getArgument(1)).size() < 2
                                 ? 1
                                 : 3);

arg是对象,所以我们必须将arg转换为我们的类型。在我的例子中,我转换了^^^ to (List)。

BDD

        ...

        given(yourMock.yourMethod(any(), anyList()))
             .willAnswer(args -> ((List) args.getArgument(1)).size() < 2
                                 ? 1
                                 : 3);

如何

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

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