My favorites | Sign in
Project Home Downloads Wiki Issues Source
READ-ONLY: This project has been archived. For more information see this post.
Search
for
CaptureParametersinjMockandEasyMock  
Capture Parameters in jMock and EasyMock.
Phase-Implementation, Phase-Support
Updated Sep 14, 2010 by John.Jian.Fang@gmail.com

MVP

I have a unit test written with jMock for a MVP framework. The presenter looks as follows:

public class MyPresenter {
    public MyPresenter(final IMyModel model, final IMyAdapter adapter) {
        // handling events between model and view
        adapter.whenScanned(new ScannedHandler() {
            public void canned() {
                String id = adapter.getScanned();
                model.retrieveShipment(id);
            }
        });

        model.whenRetrieved(new RetrievedHandler() {
            public void retrieve(Shipment shipment) {
                adapter.updateShipment(shipment);
            }
        });
    }
}

jMock

jMock uses an InstanceCatcher class to capture the handler passed in MyPresenter constructor.

public class InstanceCatcher<T> extends BaseMatcher<T> {
    private T instance;

    public T getInstance() {
        return instance;
    }

    public boolean matches(Object o) {
        try {
            instance = (T) o;
            return true;
        } catch (ClassCastException ex) {
            return false;
        }
    }
}

The magic is that jMock will call the matches method if you define the jMock object as follows:

    protected JUnit4Mockery context = new JUnit4Mockery();
    InstanceCatcher<ScannedHandler> scannedHandlerCatcher = new InstanceCatcher<ScannedHandler>();
    InstanceCatcher<ScannedHandler> retrievedHandlerCatcher = new InstanceCatcher<RetrievedHandler>();

    context.checking(new Expectations() {
      {
     one(adapter).whenScanned(with(scannedHandlerCatcher));
     one(model).whenRetrieved(with(retrievedHandlerCatcher));
      }
    });

    new MyPresenter(model, adapter);

since scannedHandlerCatcher and retrievedHandlerCatcher capture the handlers during MyPresenter initialization, we can call on the handler in unit in the following way.

context.checking(new Expectations(){{
   one(adapter).getScanned(); will(returnValue(identifier));
   one(model).retrieve(identifier);
 }});
scannedHandlerCatcher.getInstance().identifierScanned();

EasyMock

For EasyMock, I need to use the Capture command to capture the handler instance.

ScannedHandler scannedHandler;
RetrievedHandler retrievedHandler;

model = EasyMock.createMock(IMyModel.class);
adapter = EasyMock.createMock(IMyAdapter.class);
        
Capture<ScannedHandler> ishCapture= new Capture<ScannedHandler>();
adapter.whenIdentifierScanned(EasyMock.and(EasyMock.capture(ishCapture), EasyMock.isA(ScannedHandler.class)));
EasyMock.expectLastCall().once();

Capture<RetrievedHandler> sorhCapture = new Capture<RetrievedHandler>();
model.whenRetrieved(EasyMock.and(EasyMock.capture(sorhCapture), EasyMock.isA(RetrievedHandler.class)));
EasyMock.expectLastCall().once();
EasyMock.replay(adapter, model);

new MyPresenter(model, adapter);
EasyMock.verify(adapter, model);
scannedHandler = ishCapture.getValue();
retrievedHandler = sorhCapture.getValue();
EasyMock.reset(adapter, model);

After that, I can call on the handlers directly.

EasyMock.expect(adapter.getScanned()).andReturn(identifier).once();
model.retrieveShipment(identifier);
EasyMock.expectLastCall().once();
EasyMock.replay(adapter, model);
scannedHandler.identifierScanned(); 

EasyMock.verify(adapter, model);

Resources

Comment by st...@m3p.co.uk, Sep 19, 2010

in jMock, the right place to capture an argument is in an Action, not a Matcher. Matchers might be called multiple times to find an invocation, while an Action only be called once.

Comment by joe.cha...@gmail.com, Sep 22, 2011

Your JMock InstanceCatcher? class has a catch block that can never be reached. Run-time type erasure means that your cast to the unrestricted generic type parameter T will compile to a cast to java.lang.Object. Since a cast to Object cannot fail, no ClassCastException? can ever be thrown. In order to work around this, you need to pass SomeClass?.class as a parameter into the InstanceCatcher?, probably on construction. InstanceCatcher? can then use the class object to call Class.cast(). This will ensure the passsed-in object is of the appropriate type.

Powered by Google Project Hosting