web-dev-qa-db-ja.com

Mockitoでコールバックを呼び出す

私はいくつかのコードを持っています

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

Mockitoを使用してコールバックオブジェクトを取得し、callback.reply(x)を呼び出す方法

59
Kurru

それを行う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;
        }
});

(もちろんxを本来あるべきものに置き換えます)

70

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 */);
}
_

Answerは、コールバックをすぐに返す必要がある場合(読み取り:同期的に)良いアイデアですが、匿名の内部クラスを作成し、invocation.getArguments()[n]から要素を安全にキャストしないというオーバーヘッドももたらします。希望するデータ型に。また、回答内からシステムのコールバック前の状態に関するアサーションを作成する必要があります。つまり、回答のサイズと範囲が拡大する可能性があります。

代わりに、コールバックを非同期的に処理します。ArgumentCaptorを使用して、サービスに渡されるCallbackオブジェクトをキャプチャします。これで、すべてのアサーションをテストメソッドレベルで作成し、選択時にreplyを呼び出すことができます。これは、サービスが複数の同時コールバックを担当する場合に特に役立ちます。コールバックが返される順序をより詳細に制御できるためです。

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

私はこの解決策を見つけるのに多くの時間を費やしていたので、これが誰かを助けることを願っています

5
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*/);
    }
});
2
Garrett Hall