我有一些代码
service.doAction(request, Callback<Response> callback);
我该如何使用Mockito获取回调对象,并调用callback.reply(x)方法?
Answer
对象。请查看Mockito文档,位于https://static.javadoc.io/org.mockito/mockito-core/2.8.47/org/mockito/Mockito.html#answer_stubs
你可以编写类似以下内容的代码:when(mockService.doAction(any(Request.class), any(Callback.class))).thenAnswer(
new Answer<Object>() {
Object answer(InvocationOnMock invocation) {
((Callback<Response>) invocation.getArguments()[1]).reply(x);
return null;
}
});
(当然,将x
替换为应该的内容)
考虑使用ArgumentCaptor,这样做更接近于“获取回调对象”的需求。
/**
* Captor for Response callbacks. Populated by MockitoAnnotations.initMocks().
* You can also use ArgumentCaptor.forClass(Callback.class) but you'd have to
* cast it due to the type parameter.
*/
@Captor ArgumentCaptor<Callback<Response>> callbackCaptor;
@Test public void testDoAction() {
// Cause service.doAction to be called
// Now call callback. ArgumentCaptor.capture() works like a matcher.
verify(service).doAction(eq(request), callbackCaptor.capture());
assertTrue(/* some assertion about the state before the callback is called */);
// Once you're satisfied, trigger the reply on callbackCaptor.getValue().
callbackCaptor.getValue().reply(x);
assertTrue(/* some assertion about the state after the callback is called */);
}
当回调需要立即返回(同步)时,“Answer”是一个不错的选择。不过,它会引入创建匿名内部类,并将“invocation.getArguments()[n]”中的元素不安全地强制转换为所需数据类型的开销。此外,你还需要在“Answer”中对系统的前回调状态进行任何断言,这意味着你的“Answer”可能会变得越来越大。
相反地,异步处理你的回调:使用ArgumentCaptor捕获传递给服务的Callback对象。现在,你可以在测试方法级别上进行所有断言,并在选择时调用“reply”。如果你的服务负责多个同时发生的回调,这将非常有用,因为你可以更好地控制回调返回的顺序。
invocation.getArgumentAt(1, Callback.class).reply();
来避免类型安全问题。 - Stevearguments[1]
是一个 Callback,而不是一个 Object,这比编译器本身能够保证的要多。虽然不是很大的问题,但确实存在差异。 - Jeff Bowman如果你有一个这样的方法:
public void registerListener(final IListener listener) {
container.registerListener(new IListener() {
@Override
public void beforeCompletion() {
}
@Override
public void afterCompletion(boolean succeeded) {
listener.afterCompletion(succeeded);
}
});
}
那么你可以按照以下方式轻松地模拟上述方法:
@Mock private IListener listener;
@Test
public void test_registerListener() {
target.registerListener(listener);
ArgumentCaptor<IListener> listenerCaptor =
ArgumentCaptor.forClass(IListener.class);
verify(container).registerListener(listenerCaptor.capture());
listenerCaptor.getValue().afterCompletion(true);
verify(listener).afterCompletion(true);
}
我希望这可以帮助某些人,因为我花了很多时间找出这个解决方案。
when(service.doAction(any(Request.class), any(Callback.class))).thenAnswer(
new Answer() {
Object answer(InvocationOnMock invocation) {
Callback<Response> callback =
(Callback<Response>) invocation.getArguments()[1];
callback.reply(/*response*/);
}
});