74

我有一些代码

service.doAction(request, Callback<Response> callback);

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

4

4 回答 4

84

您想设置一个执行此操作的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为应有的内容)

于 2012-11-28T23:56:35.483 回答
57

考虑使用ArgumentCaptor,它在任何情况下都更接近于“grab[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 */);
}

虽然Answer当回调需要立即返回(阅读:同步)时是一个好主意,但它也引入了创建匿名内部类的开销,并且不安全地将元素从invocation.getArguments()[n]您想要的数据类型转换为。它还要求您在答案内对系统的回调前状态做出任何断言,这意味着您的答案可能会扩大规模和范围。

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

于 2012-11-29T04:04:52.970 回答
10

如果你有这样的方法:

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);
}

我希望这可能对某人有所帮助,因为我花了很多时间来找出这个解决方案。

于 2018-08-06T18:11:37.340 回答
3
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*/);
    }
});
于 2012-11-29T00:00:21.977 回答