Mockito Argument Matching in Java 8

When using mocks, we often want to check the inputs to a function that was called on the mock. It’s probably a subject for another post whether you should rely on doing this, or whether you should make more code that just returns something, rather than calls something, but let’s agree that you will, at some point, want to check how a mock’s function was called.

With Mockito as our mocking framework of choice, here’s the hard way:

// given some test execution has happened

// construct a fully-blown replica of what you think will have
// been passed into your function under test
SomeObject expectedInput = new SomeObject( ... );

verify(myMock).myMethod(eq(expectedInput));

Why is that hard?

Well, you need to predict a perfect replica of the input, which requires you to bind your test to the exact implementation. In some cases, certain fields, which are less interesting to the behaviour your testing, have to be specified so that the equals comparison works. Worse still, some fields that get arbitrary values at runtime have to have specific values pushed into them to make the test replicatable – timestamps, for instance.

In short, the above doesn’t always work well, so we often resource to the use of argument captors.

// given some test execution has happened

// Find out how the method got called
ArgumentCaptor<SomeObject> captor = ArgumentCaptor.for(SomeObject.class);
verify(myMock).myMethod(captor.capture());

// read the thing you're interested in from the captor
assertThat(captor.getValue().getInterestingProperty(), is("expected"));

Put mildly, this sucks! You have three activities to do with the captor, all of which are to enable you to check one fact. You have to construct one, use one to capture the value, and then read the value from the captor after the Mockito verify method is called. The test also reads oddly. It’s become:

  • When the test was executed
  • Given this captor
  • Check the method was called and capture
  • And check the captured value was expected

Since Mockito 2.1, used with Java 8, there has been a neater technique. You can use the argThat comparator with a verify call to inline your check in the verify method:

// given some test execution has happened

// Find out how the method got called
verify(myMock).myMethod(argThat(
        someObject -> someObject.getInterestingProperty().equals("expected")
    ));

This, I think, makes for a more straightforward test. Verify that the method was called with an argument that matches a certain filter.

The reason this is possible is that Mockito moved away from using Hamcrest internally, replacing it with its own strongly-typed ArgumentMatcher interface, which is essentially a functional interface. This means you can replace it with a lambda.

An extra bonus of this technique is that you can also use argThat within the when or given constructs in Mockito. This means you can neatly specify how your mock will behave based on nuances of the input:

when(myMock.myMethod(argThat(
        someObject -> someObject.getInterestingProperty().equals("expected")
    ))).thenReturn(42);

For more information on this please see the Mockito JavaDoc.

Advertisements

Software developer, stand-up comedian, musician, writer, jolly big cheer-monkey, skeptical thinker, Doctor Who fan, lover of fine sounds.

Posted in Java, tdd

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: