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?