This way of implementing a
MockObject in java allows any java construct to
be used to test or prepare data within the
MockObject method invocation.
The test sets up a list of expected calls. Each expected call defines an
invocation handler (implemented by an anonymous inner class). The invocation
handler must provide a method with the same name and parameters as that in
the
MockObject. The framework uses the Java1.3 Proxy class to automatically
delegate the
MockObject method invocation to the expected call invocation handler.
e.g. Suppose we have this useful helper class that we would like to test:
public class RequestWrapper {
public RequestWrapper( HttpServletRequest request ) {
this.request = request;
}
public String getName() {
return getFirstName() + " " + getLastName();
}
private String getFirstName() {
return this.request.getParameter("firstname");
}
private String getLastName() {
return this.request.getParameter("lastname");
}
private final HttpServletRequest request;
}
We need to mock the H
ttpServletRequest. The test case looks like this:
public class RequestWrapperTest extends TestCase{
public RequestWrapperTest(String name) {
super(name);
}
public static Test suite() {
return new TestSuite(RequestWrapperTest.class);
}
public static void main( String[] args) {
TestRunner.run(RequestWrapperTest.class);
}
public void test() throws Exception {
// defines the order of calls
MockCallQueue mockCallQueue = new MockCallQueue();
HttpServletRequest mockRequest = (HttpServletRequest)mockCallQueue.newMockObject( HttpServletRequest.class );
mockCallQueue.addExpectedCall( mockRequest, new LocalMockInvocationHandler() {
public String getParameter( String name ) {
assertEquals( "firstname", name );
return "Joe";
}
});
mockCallQueue.addExpectedCall( mockRequest, new LocalMockInvocationHandler() {
public String getParameter( String name ) {
assertEquals( "lastname", name );
return "Bloggs";
}
});
RequestWrapper objectUnderTest = new RequestWrapper( mockRequest );
assertEquals( "Joe Bloggs", objectUnderTest.getName() );
mockCallQueue.assertAllCallsInvoked();
}
private static abstract class LocalMockInvocationHandler extends MockInvocationHandler{
protected Object invoke( Method methodOnThis, Object[] arguments) throws InvocationTargetException, IllegalAccessException{
return methodOnThis.invoke( this, arguments );
}
}
}
Annoyingly, it is necessary to have the L
ocalMockInvocationHandler inner
class. This can be copied verbatim into any test case. The problem is that
even public methods in anonymous inner classes are not accessible outside
of the enclosing class. We can get a Method object but we can't invoke it.
The invoke method of L
ocalMockInvocationHandler means that the actual
method.invoke() is performed within a context that can access the methods
of the invocation handler.
The whole example and framework can be found in
http://www.neil.swingler.name/amock.jar
--
NeilSwingler
For simple mocks,
EasyMock is nice.
--
TammoFreese
[
CategoryMockObjects]