Spring DBUnit provides integration between the Spring test framework and the DBUnit project. In this example we show how to test a Hibernate JPA project using a Hypersonic in-memory database.
This project will be built using Apache Maven. Here is the complete POM file with all of the dependencies that we will need:
4.0.0 example spring-dbunit-example 0.0.1-SNAPSHOT <spring.version>3.0.5.RELEASE</spring.version> <hibernate.core.version>3.5.6-Final</hibernate.core.version> jboss https://repository.jboss.org/nexus/content/groups/public/ true false org.apache.maven.plugins maven-compiler-plugin 2.3.1 1.5
For this simple project we will create a single “Person” Entity with attributes for their title, first name and last name. We will also declare a query that we will make use of later.
package example.entity;
import javax.persistence.Entity; import javax.persistence.Id; import javax.persistence.NamedQueries; import javax.persistence.NamedQuery;
@Entity @NamedQueries({ @NamedQuery(name = "Person.find", query = "SELECT p from Person p where p.firstName like :name " + "or p.lastName like :name") }) public class Person {
@Id
private int id;
private String title;
private String firstName;
private String lastName;
public int getId() {
return id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
}
We also need to setup a persistence.xml file for hibernate to use:
org.hibernate.ejb.HibernatePersistence example.entity.Person
We need to have something to test so we’ll create a simple service that lets us search our Person entity using the named query from above:
package example.service;
import java.util.List;
import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; import javax.persistence.Query;
import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional;
import example.entity.Person;
@Service @Transactional public class PersonService {
@PersistenceContext
private EntityManager entityManager;
@SuppressWarnings("unchecked")
public List<Person> find(String name) {
Query query = entityManager.createNamedQuery("Person.find");
query.setParameter("name", "%"+name+"%");
return query.getResultList();
}
}
To make sure that our service is working we need to create a JUnit test. Here is the basic structure of the test class:
package example.service;
import static junit.framework.Assert.assertEquals;
import java.util.List;
import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.TestExecutionListeners; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.context.support.DependencyInjectionTestExecutionListener; import org.springframework.test.dbunit.DbUnitTestExecutionListener; import org.springframework.test.dbunit.annotation.DatabaseSetup; import org.springframework.test.dbunit.annotation.ExpectedDatabase;
import example.entity.Person;
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration @TestExecutionListeners({ DependencyInjectionTestExecutionListener.class, DbUnitTestExecutionListener.class }) public class PersonServiceTest {
@Autowired
private PersonService personService;
}
As the test is using the SpringJUnit4ClassRunner we also need a context xml configuration file. Here we tell spring to scan for beans and we also setup Hibernate and the in-memory database.
<context:component-scan base-package="example" />
<tx:annotation-driven transaction-manager="transactionManager" />
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="org.hsqldb.jdbcDriver" />
<property name="url" value="jdbc:hsqldb:mem:paging" />
<property name="username" value="sa" />
<property name="password" value="" />
</bean>
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="jpaDialect">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect"/>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
We can now create a test method to check that the service can find entities:
@Test public void testFind() throws Exception { List personList = personService.find("hil"); assertEquals(1, personList.size()); assertEquals("Phillip", personList.get(0).getFirstName()); }
At this point the test should fail because the returned personList contains 0 items. To make sure that the test passes we need to insert some database data. This is where DBUnit comes in. You may have noticed that the TestExecutionListeners annotation includes a reference to DbUnitTestExecutionListener. This means that we can use the @DatabaseSetup annotation on the test method to configure the database from a flat XML file. The xml file follows the standard DBUnit conventions:
@Test @DatabaseSetup("sampleData.xml") public void testFind() throws Exception { List personList = personService.find("hil"); assertEquals(1, personList.size()); assertEquals("Phillip", personList.get(0).getFirstName()); }
DBUnit should now execute before the test method runs to insert appropriate data into the database. As a result the test should pass.
As well as configuring the database before a test runs it is also possible to verify database set after the test completes. Let’s update our service with a method to remove entities:
... public class PersonService { ... public void remove(int personId) { Person person = entityManager.find(Person.class, personId); entityManager.remove(person); } ...
The method to test if remove works can use the @ExpectedDatabase annotation. This will use DBUnit to ensure that the database contains expected data after the test method has finshed.
@Test @DatabaseSetup("sampleData.xml") @ExpectedDatabase("expectedData.xml") public void testRemove() throws Exception { personService.remove(1); }
The sampleData.xml file is shown below:
This quick introduction has shown how Spring DBUnit can be used to setup a database and verify expected content using simple annotations.