David Williams
David Williams

Reputation: 8654

Junit/Spring/Hibernate: How to specify an out of container datasource for Hibernate Session in Unit tests

I have an applicationContext.xml which defines a bean called "baseDataSource"

<bean id="baseDataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
    <property name="resourceRef" value="true"/>
    <property name="jndiName" value="java:/MySQLDS20"/>
</bean>

Now ordinarily this is created fine within a jboss application using Spring and Hibernate. But when I try to instantiate this IOC container as part of unit testing via

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:WEB-INF/applicationContext.xml"})

I recieve this error:

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
at javax.naming.spi.NamingManager.getInitialContext(NamingManager.java:662)
at javax.naming.InitialContext.getDefaultInitCtx(InitialContext.java:307)
at javax.naming.InitialContext.getURLOrDefaultInitCtx(InitialContext.java:344)
at javax.naming.InitialContext.lookup(InitialContext.java:411)
at org.springframework.jndi.JndiTemplate$1.doInContext(JndiTemplate.java:154)
at org.springframework.jndi.JndiTemplate.execute(JndiTemplate.java:87)
at org.springframework.jndi.JndiTemplate.lookup(JndiTemplate.java:152)
at org.springframework.jndi.JndiTemplate.lookup(JndiTemplate.java:178)
at org.springframework.jndi.JndiLocatorSupport.lookup(JndiLocatorSupport.java:95)
at org.springframework.jndi.JndiObjectLocator.lookup(JndiObjectLocator.java:105)
at org.springframework.jndi.JndiObjectFactoryBean.lookupWithFallback(JndiObjectFactoryBean.java:201)
at org.springframework.jndi.JndiObjectFactoryBean.afterPropertiesSet(JndiObjectFactoryBean.java:187)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1477)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1417)

I have thoroughly read the discussion here

http://forum.spring.io/forum/spring-projects/data/7448-problem-running-junit-test-with-jndi-datasource

But no answer there seems to either solve the issue or clearly explain what is going on. My question is this:

How do I maker this datasource work? I cannot copy and paste my applicationContext.xml into some testApplicationContext.xml just for the purpose of modifying this one single bean. What can I do to create the container and autowire in my junit tests without changing this bean or duplicating the xml config (my CTO will shoot me)

Upvotes: 2

Views: 3811

Answers (3)

zg_spring
zg_spring

Reputation: 359

  1. To inject a custom JNDI context into your unit test [Gregor Koukkoullis] (this is a good method to integrate DataSource into JNDI, but you also need to init DataSource, then inject to JNDI Context)
  2. You only have to create a configuration containing only an override for the datasource [M. Deinum] (I think If you can define the datasource in new *.xml, so this method is easy to implements)

But David Williams need no copy *.xml, the purpose is very clearly, no change of configration, no change of source code, just test with JNDI.

below is my method: 1. search JNDI env in your remote Server. 2. with setup() method to init your Server JNDI properties.

then no change of configration, no change no test code, no addition datasource config, just add setup method to init remoter Server JNDI.

Upvotes: 0

M. Deinum
M. Deinum

Reputation: 124441

I cannot copy and paste my applicationContext.xml into some testApplicationContext.xml just for the purpose of modifying this one single bean.

You don't have to. You only have to create a configuration containing only an override for the datasource, then load both in your testcase.

<bean id="dataSource" class="org.springframework.jdbc.datasource.SimpleDriverDataSource>
</bean>

Then in your test case load this together with your actual file and the bean definition will override the one in your actual configuration.

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:WEB-INF/applicationContext.xml", "applicationContext-test.xml"})

The latter should only contain beans you want to override/replace.

Upvotes: 2

Gregor Koukkoullis
Gregor Koukkoullis

Reputation: 2305

To inject a custom JNDI context into your unit test you could try the following:

@BeforeClass
public static void setUp() {
    DataSource ds = null; // Construct data source manually
    ds.setURL("..."); ds.setUser("..."); ds.setPassword("...");

    SimpleNamingContextBuilder builder = null;
    try {
        builder = SimpleNamingContextBuilder.emptyActivatedContextBuilder();
        builder.bind("java:java:/MySQLDS20",ds);
    } catch (NamingException e) {
        logger.error(e);
    }
}

This will expose the required JNDI name through the InitialContext.

But I would recommend you to extract the baseDataSource into a separate configuration file and then use a specific configuration file for your tests instead. Like this:

In src/main/resources/applicationContext.xml:

<import resource="datasource.jndi.xml" />

JUnit Test Class:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({
  "classpath*:/datasource.test.xml",
})
public class MyTests
{
    ...
}

Upvotes: 2

Related Questions