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

时间:2011-11-11 00:14:27

标签: 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 (...) { }        
}

11 个答案:

答案 0 :(得分:524)

怎么样

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

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

答案 1 :(得分:200)

您可以使用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();

答案 2 :(得分:103)

作为previously pointed out几乎所有的电话都是可链接的。

所以你可以打电话给

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's Documenation中的更多信息。

答案 3 :(得分:60)

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

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

可爱不是它:)。

答案 4 :(得分: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);
    }
}

答案 5 :(得分:3)

doReturn(value1,value2,value3).when(方法调用)

答案 6 :(得分: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对象,在第二次调用时返回mock3对象,在第三次调用时返回mock2对象。 应该像when(something()).doAnswer(getAnswerForSubsequentCalls(mock1, mock3, mock2));一样使用 这与when(something()).thenReturn(mock1, mock3, mock2);

几乎相似

答案 7 :(得分:0)

与8年前@ [Igor Nikolaev]的答案有关,可以使用Java 8中的lambda expression来简化Answer的使用。

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

或更简单地说:

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

答案 8 :(得分:0)

BDD样式:

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

答案 9 :(得分:0)

这里是BDD风格的工作示例,非常简单明了

given(carRepository.findByName(any(String.class))).willReturn(Optional.empty()).willReturn(Optional.of(MockData.createCarEntity()));

答案 10 :(得分:0)

您可以使用 LinkedListAnswer。例如

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