Calling callbacks with Mockito

前端 未结 4 1803
梦毁少年i
梦毁少年i 2020-11-28 07:36

I have some code

service.doAction(request, Callback callback);

How can I using Mockito grab the callback object, and call c

相关标签:
4条回答
  • 2020-11-28 07:44

    You want to set up an Answer object that does that. Have a look at the Mockito documentation, at https://static.javadoc.io/org.mockito/mockito-core/2.8.47/org/mockito/Mockito.html#answer_stubs

    You might write something like

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

    (replacing x with whatever it ought to be, of course)

    0 讨论(0)
  • 2020-11-28 07:56

    If you have a method like:-

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

    Then following way you can mock the above method easily :-

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

    I hope this might help someone, as i had spend lot of time in figuring out this solution

    0 讨论(0)
  • 2020-11-28 08:02

    Consider using an ArgumentCaptor, which in any case is a closer match to "grab[bing] the callback object".

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

    While an Answer is a good idea when the callback needs to return immediately (read: synchronously), it also introduces the overhead of creating an anonymous inner class, and unsafely casting the elements from invocation.getArguments()[n] to the data type you want. It also requires you to make any assertions about the pre-callback state of the system from WITHIN the Answer, which means that your Answer may grow in size and scope.

    Instead, treat your callback asynchronously: Capture the Callback object passed to your service using an ArgumentCaptor. Now you can make all of your assertions at the test method level and call reply when you choose. This is of particular use if your service is responsible for multiple simultaneous callbacks, because you have more control over the order in which the callbacks return.

    0 讨论(0)
  • 2020-11-28 08:03
    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*/);
        }
    });
    
    0 讨论(0)
提交回复
热议问题