Mocking JNDI

Testing components that use JNDI to get DataSources and other resources can be annoying, because (hopefully) you don't want to run your unit tests inside the application server. JNDI is a good example of how the ServiceLocator makes testing harder.

When you can't turn around the JNDI to get your resources and inject them into your objects... it may be the case of mocking the JNDI system with something that you can control from your tests.

The File System Service Provider could be a replacement for the real JNDI system, with one that you can control easier and have it running outside the the application server.

But, another option is to mock a minimum set of the JNDI system with an in-memory implementation. This is what I did.

import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.naming.spi.InitialContextFactory;

public class InitialContextFactoryForTest implements InitialContextFactory {

    private static Context context;

    static {
        try {
            context = new InitialContext(true) {
                Map<String, Object> bindings = new HashMap<String, Object>();

                @Override
                public void bind(String name, Object obj)
                        throws NamingException {
                    bindings.put(name, obj);
                }

                @Override
                public Object lookup(String name) throws NamingException {
                    return bindings.get(name);
                }
            };
        } catch (NamingException e) { // can't happen.
            throw new RuntimeException(e);
        }
    }

    public Context getInitialContext(Hashtable<?, ?> environment)
            throws NamingException {
        return context;
    }

    public static void bind(String name, Object obj) {
        try {
            context.bind(name, obj);
        } catch (NamingException e) { // can't happen.
            throw new RuntimeException(e);
        }
    }
}

And this is an example of usage in a unit test:

import javax.naming.Context;
import javax.naming.InitialContext;
import static javax.rmi.PortableRemoteObject.narrow;
import javax.sql.DataSource;
import junit.framework.TestCase;
import com.mysql.jdbc.jdbc2.optional.MysqlConnectionPoolDataSource;

public class TestInitialContext extends TestCase {
    private DataSource dataSource;

    @Override
    protected void setUp() throws Exception {
        // sets up the InitialContextFactoryForTest as default factory.
        System.setProperty(Context.INITIAL_CONTEXT_FACTORY,
                InitialContextFactoryForTest.class.getName());

        // binds the object
        dataSource = getDataSource();
        InitialContextFactoryForTest.bind("jdbc/mysql", dataSource);
    }

    public void testInitialContext() throws Exception {
        Context ctx = new InitialContext();
        Object ref = ctx.lookup("jdbc/mysql");
        DataSource result = (DataSource) narrow(ref, DataSource.class);
        assertSame(dataSource, result);
    }

    private DataSource getDataSource() {
        MysqlConnectionPoolDataSource dataSource = new MysqlConnectionPoolDataSource();
        dataSource.setUser("username");
        dataSource.setPassword("password");
        dataSource.setServerName("server");
        dataSource.setPort(3306);
        dataSource.setDatabaseName("database");
        return dataSource;
    }

}

The InitialContextFactoryForTest.bind() method is used in the setUp() of the TestCase to bind object that will be needed by the tests, and then your code can use JNDI lookup as usual to get the resources they need.
InitialContextFactoryForTest is a very limited implementation, but it's usually enough to support most common usages of JNDI. Sometime it may be the case to extend it to support more functionalities.

Looking this post, now, I just realized that it may be the case to provide a cleanup() method on InitialContextFactoryForTest to remove all bindings (just cleaning the internal HashMap). So that the the test cases can cleanup the JNDI bindings after a test run, in tearDown() method.

But this sample is just to give an easy hint on how to workaround the JNDI when you can't keep it out from your tests.

Errata corrige: in this article I've made a little confusion on testing terms (mocks, with fake implementation). See Mocks Aren't Stubs. By the way, titling this post "Facking JNDI" would sound funny; this time I prefer keeping a certain degree of approximation over a funny accuracy.


One Response to “Mocking JNDI”  

  1. 1 Ariel

    can you adapt this example to retrieve MQ from jndi please?
    thanks

Leave a Reply

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>



Calendar

March 2009
M T W T F S S
« Feb   Apr »
 1
2345678
9101112131415
16171819202122
23242526272829
3031  

Follow me

twitter flickr LinkedIn feed

Subscribe by email

Enter your email address:

Archives


Categories

Tag Cloud


Listening