Mocking an In-memory JNDI DataSource

Learn to configure and inject an in-memory DataSource instance into JUnit tests outside any Java EE container. This is a suggested solution to test or use classes that depend on container’s (for example Tomcat) JNDI environment.

In-memory DataSource instance helps in decoupling the tests from any kind of external dependency.

1. Maven Dependency

We will be using the Simple-JNDI library’s JNDI implementation which is entirely memory-based. No server instance is started. Download its latest version from Maven repository.

<dependency>
    <groupId>com.github.h-thurow</groupId>
    <artifactId>simple-jndi</artifactId>
    <version>0.23.0</version>
</dependency>

2. Configuring JNDI Context and DataSources

To setup the initial context used by the JNDI, we need to place the jndi.properties file in the application’s classpath. As we are using this feature for unit testing, we can place the file in 'src/test/resources' directory.

java.naming.factory.initial=org.osjava.sj.SimpleContextFactory
org.osjava.sj.jndi.shared=true
jndi.syntax.separator=/
org.osjava.sj.space=java:/comp/env
org.osjava.sj.root=src/test/resources/jndi
  • java.naming.factory.initial is a part of the JNDI specification and specifies the context factory class used to create the initial context. It is a mandatory property.
  • org.osjava.sj.root is another mandatory property and points to the directory location where we store the files used to define the context objects.
  • org.osjava.sj.jndi.shared controls if all InitialContext objects will share the same memory.
  • org.osjava.sj.space – Its value is prepended to every value loaded into the system. Thus org.osjava.sj.space=java:comp/env simulates the JNDI environment of Tomcat.

Now we need to create one or multiple instances of a DataSource. So, create a property file in the directory location as configured in org.osjava.sj.root.

Simple-JNDI will load all the property files in this location. We have created one such file, datasource.properties. Here we are creating a DataSource for H2 database.

ds.type=javax.sql.DataSource
ds.driver=org.h2.Driver
ds.url=jdbc:h2:mem:testdb
ds.user=sa
ds.password=

3. Initializing DataSource in Unit Tests

To initialize a DataSource instance, start with creating an InitialContext object and lookup the Context using java:/comp/env (as specified in ‘org.osjava.sj.space’ value).

Using the Context, we can lookup datasources as configured in datasource.properties. And finally, we can use the DataSource instance further in the unit tests.

public class TestMockDataSource {

  private static InitialContext initContext;

  @BeforeAll
  public static void setup() throws Exception {
    initContext = new InitialContext();
  }

  @Test
  public void whenMockJndiDataSource_thenReturnJndiDataSource() throws Exception {
    Context envContext = (Context) this.initContext.lookup("java:/comp/env");
    DataSource ds = (DataSource) envContext.lookup("datasource/ds");

    Assertions.assertEquals(
        "org.h2.Driver::::jdbc:h2:mem:testdb::::sa", ds.toString());

    //Use the DataSource as needed

    Connection conn = ds.getConnection();
    Assertions.assertNotNull(conn);
  }

  @AfterAll
  public static void tearDown() throws Exception {
    initContext.close();
  }
}

Do not forget to close the datasources at the end.

4. Conclusion

In this short tutorial, we learned to create and inject an in-memory DataSource instance that can be used to mock J2EE container provided JNDI DataSource instance.

Happy Learning !!

Sourcecode on Github

Comments

Subscribe
Notify of
guest
0 Comments
Inline Feedbacks
View all comments

About Us

HowToDoInJava provides tutorials and how-to guides on Java and related technologies.

It also shares the best practices, algorithms & solutions and frequently asked interview questions.

Our Blogs

REST API Tutorial

Dark Mode

Dark Mode