Java – how to integration test a DAO built with spring + iBatis

daoibatisjavajunitspring

I asked a question, title of which might have been misleading so I'm going to try to ask the question again with much detailed stuff. (i know question seems long but please bear with me)

What I'm trying to do: I simply want to write a test case for my DAO and make it work. I know my DAO's work fine inside the container (app server) but when calling DAO from test case..it does not work. I think because its outside of the container.

Stuff in my spring-for-iBatis.xml

<bean id="IbatisDataSourceOracle" class="org.springframework.jndi.JndiObjectFactoryBean">
    <property name="jndiName" value="jdbc/RSRC/my/db/oltp"/>
</bean>
<bean id="MapClient" class="org.springframework.orm.ibatis.SqlMapClientFactoryBean">
  <property name="configLocation" value="classpath:sql-map-config-oracle.xml"/>
  <property name="dataSource" ref="IbatisDataSourceOracle"/>
 </bean>

Stuff in my sql-map-config-oracle.xml

<sqlMapConfig>
   <settings enhancementEnabled="true" useStatementNamespaces="true" />
 <transactionManager type="JDBC">
  <dataSource type="JNDI">
   <property name="DataSource" value="jdbc/RSRC/my/db/oltp"/>
  </dataSource>
 </transactionManager>
         <sqlMap resource="mymapping.xml"/>
</sqlMapConfig>

my Abstract class:

public abstract MyAbstract {
    public SqlMapClientTemplate getSqlTempl() SQLException{
        public static final String ORCL = "jdbc/RSRC/PIH/eiv/oltp";
        try {
            ApplicationInitializer.getApplicationContext().getBean("MapClient");
            SqlMapClient scl = (SqlMapClient) ApplicationInitializer.getApplicationContext().getBean("MapClient");
            DataSource dsc = (DataSource) MyServiceLocator.getInstance().getDataSource(ORCL);
            return new SqlMapClientTemplate (dsc, scl);
        }
        catch (NamingException e)
        {
            log.error(ne.getMessage(), e);
            throw new SQLException("some error here: " + e.getMessage());
        }
    } 
}

my DAO:

public class MyDAO extends MyAbstract{
 public AnObject getSomething(String id)
        {
        HashMap myMap = new HashMap();
        myMap.put("id", id);
        try {
            setSqlMapClientTemplate(getSqlTempl());
        }
        catch (SQLException ne)
        {
            log.error (ne.getMessage(), ne);
        }
        getSqlMapClientTemplate().queryForList("mymapping.someproc", myMap);
        return AnObject ((List)myMap.get("firstresult").get(0));
        }
}

Mytests

public class MyDAOTests extends TestCase {

 public void testMyDAO ()
 {
  MyDAO myd = new MyDAO();
  AnObject ano = myd.getSomething("15");
  assertEquals("1500", ano.getContentId());

 }
}

I've tried to present the whole problem in this code snippet. The test fails because it is not able to get the connection to the database…since it is outside the container. I know the design can be fixed to make better use of dependency injections. Can you show me, based on this snippet, what improvements could be made so that the tests would work?

I've been struggling with this and would really appreciate some help.

PS: I had to make use of setSqlMapClientTemplate() because I want call to my DAO to be just simple MyDAO myd = new MyDAO() I do not want to make interface for each one of my DAO.

Best Solution

There are lots of problems here.

First, I count three citations of the JNDI lookup string in your small example. DRY would tell you to write it once and refer to it, if possible.

Second, I don't appreciate your DAO very much. Is this really what you're writing, or is this just an example? I don't think this is the Spring idiom. There's no interface. How will you do declarative transactions without one? I'd recommend looking at the Spring docs for iBatis more carefully.

Third, I'd recommend using JUnit 4.4 or, better yet, the TestNG idiom - annotations. Also check out the Spring @ContextConfiguration to inject the beans you need in setUp.

Fourth, your DAOs cannot work because you need a JNDI lookup service running, and you can't get one without the container. The answer is to have a DriverManager data source for your tests.

UPDATE: Here's an idea to try: Use the Spring idiom for iBatis. If legacy prevents you from doing this, perhaps Spring isn't your answer.

Once you do this, all you have to do is override the data source app context to use DriverManager instead of JNDI for your test.