Mon
24
Jul '06
Mocking context lookups
by Frank Spychalski filed under Java, Work

If you find this useful, you might like my other articles, too.

Sorry for another non-ruby post, but I’m currently very busy at work playing with JBoss 4, EJB 3, EasyMock, and a bunch of other pretty cool technologies.

I’m a big fan of EasyMock but frequently I ran into problems when code performed lookups to get resources like:


Context ctx = new InitialContext();
UserTransaction trans = (UserTransaction) ctx.lookup("UserTransaction");
trans.begin();

lego elephant by TimWilson

At first it looked like I had to change the code to somehow inject my mock objects. But fortunately there is an easier, more elegant solution.

Java uses an instance of InitialContextFactory to create the InitialContext object. So the solution was to write a mock object for InitialContextFactory and tell Java to use it instead. This mock object must be a ‘real’ class (not one created with EasyMock) that can be found by reflection.


import javax.naming.Context;
import javax.naming.NamingException;
import javax.naming.spi.InitialContextFactory;
/**
 * Provides a JNDI initial context factory for the MockContext.
 */
public class MockInitialContextFactory 
  implements InitialContextFactory {
    private static Context mockCtx = null;
    public static void setMockContext(Context ctx) {
        mockCtx = ctx;
    }   
    public Context getInitialContext(java.util.Hashtable< ?, ?> environment) 
      throws NamingException {
        if (mockCtx == null) {
            throw new IllegalStateException("mock context was not set.");
        }
        return mockCtx;
    }
}

To use it for my piece of example code, I have tell Java which InitialContextFactory to use (via java.naming.factory.initial), create a mock Context, create a mock Transaction, tell the mock Context to return the Transaction. And finally tell the mock factory to return the mock Context. This sound much more complex than it actually is, here’s the same in code:

System.setProperty("java.naming.factory.initial", "MockInitialContextFactory");
Context mockCtx = createMock(Context.class);        
UserTransaction mockTrans = createMock(UserTransaction.class);
expect(mockCtx.lookup("UserTransaction")).andReturn(mockTrans);
replay(mockCtx);
MockInitialContextFactory.setMockContext(mockCtx);

2 Responses to “Mocking context lookups”

  1. 1

    Maybe the most elegant solution would be to inject a InitialContextFactory via Setter-Injection. But if you don’t use IOC, the Factory-Pattern is a good choice i think ;-)

    Daniel Cloutier (July 25th, 2006 at 09:13)
  2. 2

    The code looks exactly like the example and I didn’t want to change the code just for testing.

    Frank Spychalski (July 25th, 2006 at 11:56)

Any comments? Or questions? Just leave a Reply: