according to Twitter subscribe to my twitter feed

    Easy transactional DAO JUnit tests using Spring

    This is nice quick win from the wizards at Spring. It is all in the doco, but I thought it was worthy of a post as it is very elegant. Unit testing a traditional DAO always gives the problem of what to do with test data that gets left in the database. Even if individual developers have their own database schema that gets cleared down and set up each time your test suite runs, you can get problems with data from one test polluting the next. In the worst case, your test cases start to depend on the order in which they're run.

    Spring provides an absurdly long named, but very handy superclass for your JUnit test cases: AbstractTransactionalDataSourceSpringContextTests

    Writing your test cases in a subclass of this will mean that each case seamlessly runs in its own transaction. Spring starts a transaction before the test case method is invoked, then rolls it back on completion (pass or fail).

    Here's an example:


    package io.serg.dao;

    import java.util.Collection;
    import org.junit.Test;
    import org.springframework.test.
    AbstractTransactionalDataSourceSpringContextTests;
    import io.serg.Customer;

    public class CustomerDaoTest extends
    AbstractTransactionalDataSourceSpringContextTests {

    private ICustomerDao customerDao;

    public void setCustomerDao(ICustomerDao customerDao) {
    this.customerDao = customerDao;
    }

    @Test
    public void testGetAllCustomers() {

    Collection customers = this.customerDao.getAllCustomers();
    assertNotNull(customers);
    assertFalse(customers.isEmpty());
    }
    }


    The bean config to get this to work is very simple:

    <bean id="customerDao"
    class="io.serg.dao.CustomerDao">

    <property name="dataSource" ref="dataSource"/>
    </bean>

    <bean id="dataSource"
    class="org.apache.commons.dbcp.BasicDataSource"
    destroy-method="close">

    <property name="driverClassName" value="${jdbc.driverClass}"/>
    <property name="url" value="${jdbc.url}"/>
    <property name="username" value="${jdbc.username}"/>
    <property name="password" value="${jdbc.password}"/>
    </bean>

    <bean id="transactionManager"
    class="org.springframework.jdbc.//
    datasource.DataSourceTransactionManager">

    <property name="dataSource" ref="dataSource"/>
    </bean>


    Note that we're using Spring's autowire by type to inject the transaction manager into our unit test superclass. Still don't know what my feelings are about autowiring - my inate fear of all things magical means I'm trying to resist, but it does seem very neat in small examples like this.

    Clearly this is a very simple example, but more complex interactions with the database can be tested in this way, including the case where you do actually want to commit a transaction part way through a unit test (see the javadocs for org.springframework.test.AbstractTransactionalSpringContextTests, specifically the setComplete() method and defaultRollback property).

    This is a particularly sweet solution for the problem of unit testing your DAOs. You don’t need a separate test database per developer and you can run these concurrently and let the RDBMS handle the traffic.

    The principle argument against this technique is that you are still physically hitting the database so you are not just unit testing the DAO code. But in all honesty, unless you are going to mock up your datasource and jdbc connection (very painful) there is little alternative. In the real world, unless you go down the OR mapping route, your DAO and database are irrevicably linked. Furthermore, Spring allows you to write very clean DAOs which do almost nothing beyond handle the interaction with a relational database, so what else is there to test anyway?

    Labels: , ,



    Links to this post:

    Create a Link



    << Home