Many applications use hibernate as OR-Mapper, i want show an easy and fast way how to unit test your DAOs and domain model.
setup
we use a common use case: article ordering.
following image shows the layout of the maven project

domain model
we use hibernate annotations to define our model following code extract is taken from ArticleDTO
...
@Entity
@Table(name = "article")
public class ArticleDTO {
private long id;
private ArticleGroupEnum group;
private String name;
private double price;
private long contract;
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
@Column(name="article_id")
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
@Enumerated(EnumType.ORDINAL)
@Column(name="articlegroup")
public ArticleGroupEnum getGroup() {
return group;
}
...
spring config
as seen above we use several spring context files to define our application context.
multi-db-datasource-ctx.xml
productive datasource definition, in this example we use a mysql database and a default transaction manager
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/developersblog"/>
<property name="username" value="developer"/>
<property name="password" value="blogdevelopers"/>
<property name="initialSize" value="2" />
<property name="maxActive" value="8" />
<property name="maxIdle" value="2" />
<property name="minIdle" value="2" />
<property name="maxWait" value="-1" />
<property name="testWhileIdle" value="true"/>
</bean>
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="packagesToScan" value="org.developers.blog.db.dto"/>
<property name="hibernateProperties">
<value>
hibernate.dialect=org.hibernate.dialect.MySQLDialect
hibernate.show_sql=false
</value>
</property>
</bean>
<bean id="txManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory">
<ref local="sessionFactory" />
</property>
</bean>
multi-db-service-ctx.xml
here we define our service class, helpers,and so on ...
<bean id="dbService" class="org.developers.blog.db.DbService">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
multi-db-ctx.xml
just aggregating (import) above two context files
let's turn to our test environment
hsqldb-ctx.xml
test datasource definition (according to multi-db-datasource-ctx.xml)
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="org.hsqldb.jdbcDriver"/>
<property name="url" value="jdbc:hsqldb:mem:developersBlog"/>
<property name="username" value="sa"/>
<property name="password" value=""/>
</bean>
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="packagesToScan" value="org.developers.blog.db.dto"/>
<property name="hibernateProperties">
<value>
hibernate.dialect=org.hibernate.dialect.HSQLDialect
hibernate.format_sql=true
hibernate.hbm2ddl.auto=create
hibernate.show_sql=true
use_sql_comments=true
</value>
</property>
</bean>as you can see, we use hsqldb as in memory database..
specified property hibernate.hbm2ddl.auto=create tells hibernate to create schema definition for (in memory) database setup
import.sql
as stated in hibernate documentation, if hibernate.hbm2ddl.auto is set, hibernate searches after schema creation for an import.sql file and executes this sql script.
this is an easy to use way, to insert default data via sql into specified in memory database
INSERT INTO article (article_id, articlegroup, description, price, contract_id)VALUES ('1', '1', 'erster test article', '9.99', '2');
test class
now it's pretty easy to use this test environment. In our test class we specify above mentioned hsqldb-ctx.xml as application context as well as multi-db-service-ctx.xml and let spring autowire the beans.
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:hsql-db-ctx.xml",
"classpath:multi-db-service-ctx.xml"})
public class DbServiceIntegrationTest {
@Autowired
private SessionFactory sessionFactory;
@Autowired
private IDbService sut;
now we can answer the question, why we have an own application context file for our service bean and a seperated context file for datasource issues. Since both (production:mysql, testing:hsqldb) datasource beans have the same name, they get replaced according to used contexts.
test methods are pretty easy
/**
* simple get infos from db.
* where does this data come from ? see import.sql
*/
@Test
public void testApp() {
List<ArticleDTO> result = sut.getByContract(2);
assertEquals(1, result.size());
ArticleDTO article = result.get(0);
assertEquals(1, article.getId());
assertEquals(9.99d, article.getPrice(), 0.00d);
assertEquals(ArticleGroupEnum.FOOD, article.getGroup());
}
no need to insert/create dummy data and remove them later on. I usually add test data (statements in import.sql) for each test case.


Very useful - thanks for posting!