Friday, August 23, 2013

Using custom matchers for POJOs with Mockito...

I was trying to do the "right" thing by using TDD while working on a project, and I hit what looks to be a common problem of figuring out how to tell mock objects what to return based on whatever the argument value was that was passed in to the mock's method. It is really easy to specify which values to look for if you are dealing with a simple data type, but it isn't as straight forward if the argument is a complex object. The solution I used is the one I found on StackOverflow.

Here is the code I used:
// member of test class
private MyWorker mockMyWorker = mock(MyWorker.class);
private List<String> listOfOutputValues;
private final String theValueIWant = "some test value";

The class I am testing will use a helper class named MyWorker in this example. The class being tested will call the method MyWorker.listOutputValues(SomeObject) to get a list of output values. The SomeObject has an attribute named someValue. I only want the MyWorker class to return the output listing if the someValue matches a specific value.

I added a "when" statement in the @Before section of the test class. The "when" statement uses the custom matcher to check the value of SomeObject.getSomeValue().

@Before
private void Setup() {
 listOfOutputValues = createTestOutputValues();

 when(mockMyWorker.
                listOutputValues(argThat(hasValidAttributeValue()))).
                   thenReturn(listOfOutputValues);
}

When the mockMyWorker.listOutputValues(SomeObject) method is called in the test code, then it will return the list of Strings if SomeObject.getSomeValue() equals theValueIWant. Here is how the custom matcher is defined in the test class:
// private method in test class
private Matcher<SomeObject> hasValidAttributeValue() {
 return new BaseMatcher<SomeObject>() {
  @Override
  public boolean matches(Object o) {
   return ((SomeObject)o).getSomeValue().equals(theValueIWant);
  }

  @Override
  public void describeTo(Description description) {

  }
 };
}

No comments:

Post a Comment