Returning Parameters in JMock 2
If you have a method like:
String getParameter(String name, String defaultValue)
where defaultValue is returned if the parameter isn’t specified, it can be challenging to get the right behavior in JMock without just hard coding what the defaultValue should be. Fortunately, a custom match which doubles as an Action can solve this pretty easily:
import org.hamcrest.*;
import org.jmock.api.*;
public class CapturingMatcher<T> extends BaseMatcher<T> implements Action {
public T captured;
public boolean matches(Object o) {
try {
captured = (T)o;
return true;
} catch (ClassCastException e) {
return false;
}
}
public void describeTo(Description description) {
description.appendText("captured value ");
description.appendValue(captured);
}
public Object invoke(Invocation invocation) throws Throwable {
return captured;
}
}
It can then be used like:
context.checking(new Expectations() {{
CapturingMatcher<String> returnCapturedValue = new CapturingMatcher<String>();
allowing(mockObject).getParameter(with(equal("expectedParameterName")), with(returnCapturedValue)); will(returnCapturedValue);
}});
The matcher is used both for the parameter value (which it stores) and the return action, so it acts like a back reference would in a regex. The same class be be useful alone as a matcher to let you interrogate the parameter value using normal assert statements rather than building a custom matcher.
I really should investigate what the describeTo function really should do though – I’m sure it would generate pretty weird messages at the moment.

March 10th, 2010 at 3:32 am
Slightly off topic, but from this post note that you’re using Jmock for mocking framework. Have you ever looked at Mockito? http://code.google.com/p/mockito/
I’ve found it’s much more intuitive than other mocking frameworks. Supports hamcrest as well, so with similar CapturingMatcher def as you’ve got (implementing Answer instead of Action), you would end up having something like:
when(mockObject.getParameter(eq(“expectedParameterName”), argThat(returnCapturedValue )).thenAnswer(returnCapturedValue);
March 10th, 2010 at 9:47 am
Yeah I’ve seen Mockito, there’s not really enough that’s better to justify rewriting everything. JMock 2 has a very friendly syntax, with the only weird bit being the context.checking wrapper. I think the JMock API is actually much easier to read than Mockito in many ways, mostly because it uses full words (equal instead of eq) and better matching normal lingo – e.g. will(returnValue(…)) instead of thenAnswer since Java returns things it doesn’t answer.
It’s all much a muchness though.
March 10th, 2010 at 11:00 am
Thanks for posting the tip. describeTo() is intended to help you understand what has happened when it goes wrong.
I’m curious, though, as to why this trick is necessary in a unit test. Surely you know what the expected default value should be?
March 10th, 2010 at 11:07 am
I suppose you could assert that it’s passing in a specific default value just as easily and then you’d know what to return, but that defines more about the implementation than I think a test really should (at least in this case). I probably would have just done that if I didn’t already have the capturing matcher around to make my life easier with complex asserts. In this case the mock is half stub/half mock so I want to be as loose as possible in what method calls and arguments are used (mostly) and just assert that the result is correct.
January 5th, 2011 at 2:49 pm
I like your solution but I’m not a fan of catching the ClassCastException. Here’s a revision using TypeSafeMatcher that gets rid of the try-catch;
class CapturingMatcher extends TypeSafeMatcher implements Action {
public T captured;
public void describeTo(Description description) {
description.appendText(“captured value “);
description.appendValue(captured);
}
public Object invoke(Invocation invocation) throws Throwable {
return captured;
}
@Override
public boolean matchesSafely(T arg) {
captured = (T)arg;
return true;
}
}
January 5th, 2011 at 2:53 pm
Nice. Not sure why I didn’t notice the TypeSafeMatcher class when I was originally doing this.