Mock Objects By Delegate

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 HttpServletRequest. 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 LocalMockInvocationHandler 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 LocalMockInvocationHandler 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]


EditText of this page (last edited September 9, 2002) or FindPage with title or text search