How to test a mocked JNDI datasource with Spring?

You can use SimpleNamingContextBuilder to make a jndi datasource available to your tests:

    SimpleNamingContextBuilder builder = new SimpleNamingContextBuilder();
    builder.bind("java:comp/env/jdbc/mydatasource", dataSource);
    builder.activate();

https://fisheye.springsource.org/browse/spring-framework/spring-test/src/main/java/org/springframework/mock/jndi/SimpleNamingContextBuilder.java?hb=true

This isn't exactly mocking the datasource, but it does make the datasource available via jndi for your tests.


You can create your own mock DataSource by extending Spring's AbstractDataSource.

import java.sql.Connection;
import java.sql.SQLException;

import org.springframework.jdbc.datasource.AbstractDataSource;

/**
 * Mock implementation of DataSource suitable for use in testing.
 * 
 *
 */
public class MockDataSource extends AbstractDataSource {
    private Connection connection;

    /**
     * Sets the connection returned by javax.sql.DataSource#getConnection()
     * and javax.sql.DataSource#getConnection(java.lang.String, java.lang.String)
     * 
     * @param connection
     */
    public void setConnection(Connection connection) {
        this.connection = connection;
    }

    /*
     * (non-Javadoc)
     * @see javax.sql.DataSource#getConnection()
     */
    public Connection getConnection()
            throws SQLException {
        return connection;
    }

    /*
     * (non-Javadoc)
     * @see javax.sql.DataSource#getConnection(java.lang.String, java.lang.String)
     */
    public Connection getConnection(String username, String password)
            throws SQLException {
        return connection;
    }
}

I'd separate the JNDI lookup of the connection from the rest of the code. Inject the DataSource into your Data Access Objects (DAOs) and use the MockDataSource for testing the DAOs.


I usually define my JNDI dependencies in seperate file, like datasource-context.xml:

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:jee="http://www.springframework.org/schema/jee"
    xmlns:p="http://www.springframework.org/schema/p"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans 
        http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
        http://www.springframework.org/schema/jee
        http://www.springframework.org/schema/jee/spring-jee-3.0.xsd">

    <jee:jndi-lookup id="dataSource" 
        jndi-name="java:comp/env/dataSource" 
        expected-type="javax.sql.DataSource" />

</beans>

So that in test resources I can create another file and define the test datasource however it suits me, like datasource-testcontext.xml:

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:p="http://www.springframework.org/schema/p"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans 
        http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

    <bean id="dataSource"
        class="org.springframework.jdbc.datasource.DriverManagerDataSource"
        p:driverClassName="org.hsqldb.jdbcDriver"
        p:url="jdbc:hsqldb:hsql://localhost:9001"
        p:username="sa"
        p:password="" /> 

</beans>

And then in my test class I use the test configuration of the datasource instead of production one that depends on JNDI:

@ContextConfiguration({
    "classpath*:META-INF/spring/datasource-testcontext.xml",
    "classpath*:META-INF/spring/session-factory-context.xml"
})
public class MyTest {

}

If the data source is not defined in a separate file You can still stub the object returned by JNDI calls easily:

  • like this: Injecting JNDI datasources for JUnit Tests outside of a container
  • or using classes in package org.springframework.mock.jndi, ie. SimpleNamingContextBuilder (there's an example in the javadoc of this calass).

You can allways create a beans.test.xml configuration, where you first reference the beans.xml, and then override the datasource configuration:

src/main/resources/beans.xml

<!-- Database configuration -->
<import resource="beans.datasource.jndi.xml" />

src/test/resources/beans.test.xml

<import resource="beans.xml" />
<import resource="beans.datasource.test.xml" />

JUnit Test Class:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "classpath:/beans.test.xml" })
public class ASRTests
{
...
}

In your jndi bean, declare the reference

<jee:jndi-lookup expected-type="javax.sql.DataSource" id="mysqlDataSource" jndi-name="jdbc/mysql"/>

In your test bean, declare the datasource

<bean id="mysqlDataSource" ...>
...
</bean>

Keep in mind to move the test datasource bean into test folder.