Search code examples
javaspringjunitjbossjndi

How to run JUnit Test in Spring Injecting JBOSS JNDI datasources


I have an application in spring with database oracle running on JBOSS 7.1. I want to test my service layer beans simply running a junit test. In my spring context I use a jndi datasource like this:

<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
    <property name="jndiName" value="jboss/datasources/myDatasource" />
    <property name="resourceRef" value="true"/>
</bean>

When I run my junit test that loads the spring context test I receive an exception like:

java.lang.IllegalStateException: Failed to load ApplicationContext
    at org.springframework.test.context.TestContext.getApplicationContext(TestContext.java:157)
    at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.injectDependencies(DependencyInjectionTestExecutionListener.java:109)
...
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dataSource' defined in class path resource [context.xml]: Invocation of init method failed; nested exception is 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 org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1455)

How can I inject the JNDI datasource in my tests without change my context in jboss?


Solution

  • According with this post, or this great blog post I found three ways to solve my issue, just create BeforeClass method in your JUnitTest Class.

    I post it for the community:

    - Solution 1
    This solution, requires the catalina.jar and the oracledriver in your classpath:

    @BeforeClass
    public static void setUpClass() throws Exception {
        try {
            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("jboss");
            ic.createSubcontext("jboss/datasources");
            ic.createSubcontext("jboss/datasources/myDatasource");
    
            OracleConnectionPoolDataSource ds = new OracleConnectionPoolDataSource();
            ds.setURL("jdbc:oracle:thin:@xxxxx:1521:xxxxx");
            ds.setUser("myUserid");
            ds.setPassword("myPass");
    
            ic.rebind("jboss/datasources/myDatasource", ds);
        } catch (NamingException ex) {
            ex.printStackTrace();
        }
    }
    

    if you use maven you can put in your pom:

    <dependency>
        <groupId>org.apache.tomcat</groupId>
        <artifactId>catalina</artifactId>
        <version>6.0.37</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>com.oracle</groupId>
        <artifactId>ojdbc6</artifactId>
        <version>11.2.0.3.0</version>
        <scope>test</scope>
    </dependency> 
    


    - Solution 2
    This solution, requires commons-dbcp in your classpath:

    @BeforeClass
    public static void setUpDataSource() throws Exception {
        try {
            SimpleNamingContextBuilder builder = new SimpleNamingContextBuilder();
            DriverAdapterCPDS cpds = new DriverAdapterCPDS();
            cpds.setDriver("oracle.jdbc.OracleDriver");
            cpds.setUrl("jdbc:oracle:thin:@xxxxx:1521:xxxxx");
            cpds.setUser("myUsername");
            cpds.setPassword("myPass");
    
            SharedPoolDataSource dataSource = new SharedPoolDataSource();
            dataSource.setConnectionPoolDataSource(cpds);
            dataSource.setMaxActive(10);
            dataSource.setMaxWait(50);
            builder.bind("jboss/datasources/myDatasource", dataSource);
            builder.activate();
        } catch (NamingException ex) {
            ex.printStackTrace();
        }
    }
    

    in your pom:

    <dependency>
        <groupId>commons-dbcp</groupId>
        <artifactId>commons-dbcp</artifactId>
        <version>1.4</version>
        <scope>test</scope>
    </dependency>
    


    - Solution 3
    This solution uses the OracleConnectionPoolDataSource included in Oracle Driver:

    @BeforeClass
    public static void setUpDataSource() throws Exception {
        try {
            SimpleNamingContextBuilder builder = new SimpleNamingContextBuilder();
    
            OracleConnectionPoolDataSource ds = new OracleConnectionPoolDataSource();
            ds.setURL("jdbc:oracle:thin:@xxxxx:1521:xxxxx");
            ds.setUser("myUsername");
            ds.setPassword("myPass");           
    
            builder.bind("jboss/datasources/myDatasource", ds);
            builder.activate();
        } catch (NamingException ex) {
            ex.printStackTrace();
        }
    }