Can I avoid redefining JNDI datasource when using JUnit?

Viewed 2200

My Java EE 7 app, which uses Spring, runs on Tomcat 7. It accesses a database by using a JNDI datasource, defined by this line in context.xml:

<Resource auth="Container" driverClassName="org.postgresql.Driver" maxActive="100" maxIdle="30" maxWait="10000" name="jdbc/leadmanager" password="xxxxxxxx" type="javax.sql.DataSource" url="jdbc:postgresql://localhost:5432/leadmanager" username="postgres"/>

I created some JUnit tests. When I tried to run them (in Eclipse, by right-clicking the test class and selecting Run As | JUnit Test), an exception occurred:

javax.persistence.PersistenceException: [PersistenceUnit: leadmanager] Unable to build EntityManagerFactory
...
Caused by: org.hibernate.service.jndi.JndiException: Error parsing JNDI name [java:/comp/env/jdbc/leadmanager]
...
Caused by: javax.naming.NoInitialContextException: Need to specify class name in environment or system property, or as an applet parameter, or in an application resource file:  java.naming.factory.initial
...

Thanks to this helpful post -- https://blogs.oracle.com/randystuph/entry/injecting_jndi_datasources_for_junit -- I found a solution. I added this to my test class:

@BeforeClass
public static void setUpClass() throws Exception {

    // create initial context
    System.setProperty(Context.INITIAL_CONTEXT_FACTORY, "org.apache.naming.java.javaURLContextFactory");
    System.setProperty(Context.URL_PKG_PREFIXES, "org.apache.naming");            
    InitialContext ic = new InitialContext();

    ic.createSubcontext("java:");
    ic.createSubcontext("java:/comp");
    ic.createSubcontext("java:/comp/env");
    ic.createSubcontext("java:/comp/env/jdbc");

    PGPoolingDataSource ds = new PGPoolingDataSource();
    ds.setServerName("localhost:5432/leadmanager");
    ds.setUser("postgres");
    ds.setPassword("xxxxxxxx");
    ic.bind("java:/comp/env/jdbc/leadmanager", ds);
}

But that's hideous! I'm forced to define my datasource twice, once in context.xml and again in my test class. And I'm forced to store my database password in Java code that's going to be checked in to source control.

I've already consulted this post, as well: Setting up JNDI Datasource in jUnit

Is there a better way?

2 Answers

You can also use TomcatJNDI. It reads Tomcat's configuration files and creates a JNDI environment as in your web application. It is as easy as this code example:

TomcatJNDI tomcatJNDI = new TomcatJNDI();
tomcatJNDI.processContextXml(contextXmlFile);
tomcatJNDI.start();

Now you can access all your resources you have declared in Tomcat's configuration files.

Find out more about it here.

Related