Mockito verify that a specific lambda has been passed as an argument to the layout method

I want to test the following method:

public void dispatchMessage(MessageHandler handler, String argument1, String argument2, Long argument3) { handler.registerMessage(() -> { dispatcher.dispatch(argument1, argument2, argument3); }); } 

Where MessageHandler is a helper class that takes an implementation of a functional interface in the form of a lambda and stores it for later execution.

Is there a way to verify with mockito that the dispatchMessage method of the mocking MessageHandler was called with a specific lambda expression:

Sense, can I write such a test:

  @Test public void testDispatchMessage_Success() throws Exception { myMessageDispatcher.dispatchMessage(handler, "activityId", "ctxId", 1l, ); verify(handler, times(1)).dispatchMessage(() -> { dispatcher .dispatch("activityId", "ctxId", 1l,); }); } } 

This test will result in a statement error: The arguments are different! Required:

 ......Tests$$Lambda$28/ 379645464@48f278eb 

The actual call has different arguments:

 ..........Lambda$27/ 482052083@2f217633 

which makes sense since mockito is trying to compare two different functional interface implementations that have a different hash code.

So, is there any other way to verify that the dispatchMessage() method was called with a lambda that returns void and has the body method dispatcher.dispatch("activityId", "ctxId", 1l,); ?

+5
source share
1 answer

Yes, you can. The trick here is that you need to get to the lambda instance that is passed to registerMessage , and then execute that expression, and then you can check the result.

For the purposes of a meaningful example, I created this Handler class containing the dispatchMessage that you want to check:

 public class Handler { private Dispatcher dispatcher = new Dispatcher(); public void dispatchMessage(MessageHandler handler, String argument1, String argument2, Long argument3) { handler.registerMessage(() -> { dispatcher.dispatch(argument1, argument2, argument3); }); } interface MessageHandler { void registerMessage(Runnable run); } static class Dispatcher { void dispatch(String a, String b, long c){ // Do dispatch } } } 

What you should remember is that the lambda expression is just a short form for passing a function to a method. In this example, the function is the run method of the Runnable . Therefore, the registerMessage method of the interface for MessageHandler accepts Runnable as an argument. I also included an implementation for Dispatcher that is called from registerMessage . The test for this is as follows:

 @RunWith(MockitoJUnitRunner.class) public class HandlerTest { @Mock private Dispatcher dispatcher; @InjectMocks private Handler classUnderTest; @Captor private ArgumentCaptor<Runnable> registerMessageLambdaCaptor; @Test public void shouldCallDispatchMethod() { final String a = "foo"; final String b = "bar"; final long c = 42L; MessageHandler handler = mock(MessageHandler.class); classUnderTest.dispatchMessage(handler, a, b, c); verify(handler).registerMessage(registerMessageLambdaCaptor.capture()); Runnable lambda = registerMessageLambdaCaptor.getValue(); lambda.run(); verify(dispatcher).dispatch(a, b, c); } } 

There is an ArgumentCaptor expression for the lambda expression that we use when we first check registerMessage . After this check, we can get the lambda expression from the invader. The expression type is a Runnable lambda, as defined in the MessageHandler interface. Therefore, we can call the run method on it, and then verify that the dispatch method on the Dispatcher was called with all the relevant arguments.

+5
source

Source: https://habr.com/ru/post/1262287/


All Articles