Использование Mockito с несколькими вызовами одного и того же метода с теми же аргументами
Есть ли способ, чтобы зашитый метод возвращал разные объекты при последующих вызовах? Я хотел бы сделать это, чтобы проверить неопределенные ответы от 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 (...) { }
}
Ответы
Ответ 1
Вы можете сделать это с помощью метода 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
Как насчет
when( method-call ).thenReturn( value1, value2, value3 );
В скобках thenReturn вы можете указать столько аргументов, сколько хотите, при условии, что они все правильные. Первое значение будет возвращено при первом вызове метода, затем втором ответе и т.д. Последнее значение будет возвращено повторно, когда все остальные значения будут использованы.
Ответ 3
Как уже отмечалось , почти все вызовы связаны с цепочкой.
Итак, вы можете позвонить
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();
Дополнительная информация в Mokito Documenation.
Ответ 4
Вы можете даже вызвать вызовы метода doReturn()
, подобные этому
doReturn(null).doReturn(anotherInstance).when(mock).method();
мило, не так ли:)
Ответ 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);
}
}
Ответ 6
В качестве обычного метода можно использовать разные аргументы для разных вызовов методов. Единственное, что нам нужно сделать, - это передать массив с порядком, в котором объекты должны быть получены в каждом вызове.
@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;
}
}
}
Ex. getAnswerForSubsequentCalls(mock1, mock3, mock2);
вернет объект mock1 при первом вызове, объект mock3 во втором вызове и объект mock2 при третьем вызове.
Должен использоваться как when(something()).doAnswer(getAnswerForSubsequentCalls(mock1, mock3, mock2));
Это почти похоже на when(something()).thenReturn(mock1, mock3, mock2);
Ответ 7
Относительно @[Игоря Николаева] ответа 8 лет назад использование Answer
можно несколько упростить с помощью лямбда-выражения, доступного в Java 8.
when(someMock.someMethod()).thenAnswer(invocation -> {
doStuff();
return;
});
или проще:
when(someMock.someMethod()).thenAnswer(invocation -> doStuff());
Ответ 8
Стиль BDD:
import static org.mockito.BDDMockito.*;
...
@Test
void submit() {
given(yourMock.yourMethod()).willReturn(1, 2, 3);