Sunday, 28 October 2012

Spring-Test DBUnit

I recently came accross a project on github, called Spring-Test DBUnit. It provides a bunch of annotations to easily integrate dbunit with junit to create integration tests. I will quickly outline a simple use case for configuring the spring-test-dbunit in a spring app.

Firstly add the following dependencies to your pom.xml
<dependency>
      <groupid>org.dbunit</groupId>
      <artifactid>dbunit</artifactId>
      <version>2.4.8</version>
      <type>jar</type>
      <scope>test</scope>
  </dependency>
   
  <dependency>
      <groupid>com.github.springtestdbunit</groupId>
      <artifactid>spring-test-dbunit</artifactId>
      <version>1.0.0</version>
      <scope>test</scope>
  </dependency>
  
  
  <!-- Logging required by spring-test-dbunit -->
  <dependency>
      <groupid>ch.qos.logback</groupId>
      <artifactid>logback-classic</artifactId>
      <version>1.0.7</version>
  </dependency>

Now in your java add the following annotations
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations= {
  "classpath:config/db.xml",
})
@DbUnitConfiguration(databaseConnection="dataSource")
@TestExecutionListeners({
  DependencyInjectionTestExecutionListener.class,
  DirtiesContextTestExecutionListener.class,
  TransactionDbUnitTestExecutionListener.class, //<-- needed if using transactions otherwise use TransactionalTestExecutionListener.class
  DbUnitTestExecutionListener.class })
@TransactionConfiguration(transactionManager="transactionManager", defaultRollback= false)
public class DbUnitConfigTest extends DbUnitTestTemplate {

  @Test
  @DatabaseSetup(value="test_data.xml", type=DatabaseOperation.CLEAN_INSERT)
  @DatabaseTearDown(value="test_data.xml", type=DatabaseOperation.DELETE_ALL)
  @Transactional
  public void test01()
  {
    //some code
  }

}
- @DatabaseTearDown will delete data define in xml in reverse order to avoid contraint issues The first 12 lines of the class would usually be the same for each test, They define project and db configuration. it makes good sense to create an abstract class with only those annotations like this
@DbUnitConfiguration(databaseConnection="dataSource")
@TestExecutionListeners({
  DependencyInjectionTestExecutionListener.class,
  DirtiesContextTestExecutionListener.class,
  TransactionDbUnitTestExecutionListener.class,
  DbUnitTestExecutionListener.class })
@TransactionConfiguration(transactionManager="transactionManager", defaultRollback= false)
public abstract class DbUnitTestTemplate {


}
So now your tests only need to define the test data. like
@RunWith(SpringJUnit4ClassRunner.class)
public class DbUnitConfigTest extends DbUnitTestTemplate {

  @Test
  @DatabaseSetup(value="test_data.xml")
  @DatabaseTearDown(value="test_data.xml")
  @Transactional
  public void test01()
  {

  }
}
@DatabaseSetup, @DatabaseTearDown can be added at class level to load test data once for all tests and then tear down once all tests in class have completed. There also some other cool features provided by the library, be sure to check out the lib at http://springtestdbunit.github.com/spring-test-dbunit


2 comments:

  1. you save my day!!! thank you

    ReplyDelete
  2. I guess I forgot @DatabaseTearDown. Thanks for writing this.

    ReplyDelete