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”
Leave a Reply
Search
Calendar
| M | T | W | T | F | S | S |
|---|---|---|---|---|---|---|
| « Feb | Apr » | |||||
| 1 | ||||||
| 2 | 3 | 4 | 5 | 6 | 7 | 8 |
| 9 | 10 | 11 | 12 | 13 | 14 | 15 |
| 16 | 17 | 18 | 19 | 20 | 21 | 22 |
| 23 | 24 | 25 | 26 | 27 | 28 | 29 |
| 30 | 31 | |||||
Archives
Categories
Tag Cloud
Android API Bash Bios CSS Development Eclipse Encription Error Handling Font Git Google GWT Hardware How-To HTML Installation iPod Java JavaScript Karmic Linux Lucks MacBook Open Source Opinion OSX Pitfalls Pkg Practices Python Resume Security Software Suspend TDD Testing Tools Top Down Tricks Ubuntu Uninstall Wakup On Lan Web Workaround
WP Cumulus Flash tag cloud by Roy Tanck and Luke Morton requires Flash Player 9 or better.
Blog License
Blogs I like
Books on the desk
Friends' Blogs
- Antonio Terreno & Valter Bernardini
- Bruno Bossola
- Daniele Galluccio
- Domenico Ventura
- Ed Schepis
- Fabrizio Gianneschi
- Luca Grulla
- Luigi Zanderighi
- Marcello Teodori
- Mida Boghetich
- Muralidharan Chandrasekaran
- Piero Ricca
- Renzo Borgatti
- Simone Bordet
- Simone Bruno
- Uberto Barbini
- Valvolog
- Webtide blogs (Greg Wilkins & Jan Bartel)
Links





















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