0

I have some troubles testing my application, whereas it works well in normal execution. I think it comes from JNDI resources which are not found, but I don't understand why and how to fix it.

When I start my Junit test, I got this error:

java.lang.IllegalStateException: Failed to load ApplicationContext
    at org.springframework.test.context.CacheAwareContextLoaderDelegate.loadContext(CacheAwareContextLoaderDelegate.java:99)
    at ...
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'DAOImpl': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private javax.sql.DataSource com.sample.DAOImpl.myDatasource; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [javax.sql.DataSource] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true), @org.springframework.beans.factory.annotation.Qualifier(value=myDatasource)}
Related cause: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'myDatasource' defined in URL [file:src/test/resources/spring/test-dao-config.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.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:288)
    at ...
Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire field: private javax.sql.DataSource com.sample.DAOImpl.myDatasource; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [javax.sql.DataSource] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true), @org.springframework.beans.factory.annotation.Qualifier(value=myDatasource)}
    at ...
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [javax.sql.DataSource] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true), @org.springframework.beans.factory.annotation.Qualifier(value=myDatasource)}
    at ..

Here is my configuration:

Context.xml

<Resource name="jdbc/myDatasource" auth="Container" type="javax.sql.DataSource"
    driverClassName="oracle.jdbc.OracleDriver"
    url="jdbc:oracle:thin:@database:99999:instance"
    username="user"
    password="password"
    validationQuery="select 1 from dual"
    testOnBorrow ="true"
    maxActive="5"
    maxIdle="1"
    maxWait="-1" />

test-dao-config.xml

<bean id="myDatasource" class="org.springframework.jndi.JndiObjectFactoryBean">
    <property name="jndiName" value="java:comp/env/jdbc/myDatasource" />
</bean>

DaoImpl

@Repository
public class DacsDAOImpl implements DacsDAO
{
    private final static Logger LOGGER = LoggerFactory.getLogger(DAOImpl.class);

    @Autowired
    @Qualifier("myDatasource")
    private DataSource myDatasource;

    ....
}

And my tests

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "file:src/test/resources/spring/test-dao-config.xml" })
public class MyDAOImplTest
{
    private MyDAO dao;

    @BeforeClass
    public static void initJndi() throws IllegalStateException, NamingException
    {
        //some test, but doesn't work

//      SimpleNamingContextBuilder builder = SimpleNamingContextBuilder.emptyActivatedContextBuilder();
//      builder.bind("java:comp/env/jdbc/myDatasource", "myDatasource");
//      builder.activate();
    }

    @Before
    public void setUp() throws IllegalStateException, NamingException
    {
        dao = new MyDAOImpl();
    }

    @Test
    public void testTotalUser()
    {
        int result = dao.getTotalUser();
        Assert.assertEquals(0, result);
    }
}

Thanks

thibon
  • 360
  • 2
  • 7
  • 19

1 Answers1

0

You are running in a test case so everything in your Context.xml isn't available as that is only available on tomcat. Why do you need a jndi lookup in your test case anyway? If you want to test your dao use an in-memory database like hsql, h2 or derby and use that instead. Spring has some nice tags to make it easy for you.

<jdbc:embedded-database id="myDataSource" type="H2">
    // Add some init scripts here.
</jdbc:embedded-database>

If you really need to do a JNDI lookup you are almost there in your test case. However you have to register a DataSource not a String. So you still will need to construct some (in-memory) datasource and bind that to the mock jndi location

@BeforeClass
public static void initJndi() throws IllegalStateException, NamingException
{
    //some test, but doesn't work
    // Construct in-memory database
  SimpleNamingContextBuilder builder = SimpleNamingContextBuilder.emptyActivatedContextBuilder();
  builder.bind("java:comp/env/jdbc/myDatasource", myDatasource);  //Actual datasource not a String!
  builder.activate();
}

And finally your test is also flawed, you are loading your context but aren't doing anything with it. You are constructing a MyDAOImpl in your @Before method. Why even bother loading the context as you are doing nothing with.

M. Deinum
  • 115,695
  • 22
  • 220
  • 224
  • Actually, datasource is an autowired property of daoImpl. And I know there are embedded database like H2, and I will use it next but I want to make my test to work before adding something I don't know yet – thibon Mar 18 '14 at 09:59
  • That isn't going to work. You don't have JNDI available as I already mentioned. You will not be able to connect to your actual database unless you copy the configuration from the context.xml, configure an actual `DataSource` which points to your actual database. Then you have to use the `SimpleNamingContextBuilder` to add it to your mock JNDI tree. – M. Deinum Mar 18 '14 at 10:07
  • I finally did it with embedded database, since it seems simpler than jndi – thibon Mar 18 '14 at 12:10