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 which will accept a Functional Interface implementation in the form a lambda, and store it for later execution.
Is there a way to verify with mockito that the dispatchMessage
method of the mocked MessageHandler
has been called with the specific lambda expression:
Meaning, 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 assertion error: Argument(s) are different! Wanted:
......Tests$$Lambda$28/379645464@48f278eb
Actual invocation has different arguments:
..........Lambda$27/482052083@2f217633
which makes sense since mockito tries to compare two different implementations of the functional interface, which have a different hash code.
So is there some other way to verify that the method dispatchMessage()
has been called with a lambda that returns void and has a body method of dispatcher.dispatch("activityId", "ctxId", 1l,);
?
Yes, you can. The trick here is that you have to get to the instance of the lambda that is passed to the registerMessage
and then execute that expression and then you can verify the result.
For the purpose of a meaningful example I created this Handler
class that contains the dispatchMessage
that you want to test:
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 have to remember is that a lambda expression is just a short hand form to pass a function to a method. In this example the function is the run
method of a Runnable
. Therefore the method registerMessage
of the interface for MessageHandler
takes a Runnable
as it's argument. I also included an implementation for the Dispatcher
, which is called from within registerMessage
. The test for this looks like this:
@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
for the lambda expression which we use in the first verification of the registerMessage
. After that verification we can retrieve the lambda expression from the captor. The type of the lambda expression is Runnable
, as defined in the MessageHandler
interface. Hence we can call the run
method on it and then verify that the dispatch
method on the Dispatcher
was called with all the appropriate arguments.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With