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.
I was reminded on the weekend of how much I like working with parser generators – they’re just so pure and clean. You really feel like you’re working with a grammar and all those CS lectures come flooding back. Writing code to parse the same content by hand just never has that feel. Plus they create incredibly accurate parsers in very little time at all.
