用Mockito调用回调

Kur*_*rru 61 java testing mockito

我有一些代码

service.doAction(request, Callback<Response> callback);
Run Code Online (Sandbox Code Playgroud)

如何使用Mockito获取回调对象,并调用callback.reply(x)

Daw*_*ica 73

您想要设置一个Answer执行该操作的对象.请访问https://static.javadoc.io/org.mockito/mockito-core/2.8.47/org/mockito/Mockito.html#answer_stubs查看Mockito文档.

你可能会写类似的东西

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

(x当然,取而代之的是它应该是的)

  • 顺便说一下,如果函数返回void,则需要执行doAnswer(...).when(mockedObject).method(any(Callback [] .class)); 如http://stackoverflow.com/questions/3581754/using-mockito-how-do-i-intercept-a-callback-object-on-a-void-method所述 (40认同)

Jef*_*ica 50

考虑使用ArgumentCaptor,它在任何情况下都更接近于"抓住[bing]回调对象".

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

虽然Answer回调需要立即返回(读取:同步)时是一个好主意,但它也会引入创建匿名内部类的开销,并且不安全地将元素转换invocation.getArguments()[n]为所需的数据类型.它还要求您从"答案"中包含有关系统预回调状态的任何断言,这意味着您的答案的大小和范围可能会增大.

相反,异步处理回调:使用ArgumentCaptor捕获传递给服务的Callback对象.现在,您可以在测试方法级别进行所有断言,并reply在选择时进行调用.如果您的服务负责多个同时回调,则此功能特别有用,因为您可以更好地控制回调返回的顺序.


Sum*_*aha 6

如果您有以下方法:

public void registerListener(final IListener listener) {
    container.registerListener(new IListener() {
        @Override
        public void beforeCompletion() {
        }

        @Override
        public void afterCompletion(boolean succeeded) {
            listener.afterCompletion(succeeded);
        }
    });
}
Run Code Online (Sandbox Code Playgroud)

然后按照以下方式可以轻松模拟上述方法:-

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

我希望这对某人有帮助,因为我花了很多时间来解决这个问题