We would like to properly test the DAO layer, but there are some issues when using for example the J2EE stack in combination with JPA
Your entity manager will be created by the application server, so for now its not unit testable in an easy way.
That’s where Spring comes in, with a little help from unitils, you will have your set-up in no time!
We will need a unitils.properties, unitils-local.properties, a spring context and a persistence-local.xml
Lets start with the persistence-local.xml. Why cant we use the real one? Most of the settings of the persistence file can be overridden by Spring, but there is one setting that cant be overriden. The transaction-type, it should be RESOURCE_LOCAL
<persistence-unit name="persistence-one" transaction-type="RESOURCE_LOCAL">
In the unitils.properties you do not need to adapt that much. Your default unitils set-up should do. But you have to turn of the transactional proxy.
dataSource.wrapInTransactionalProxy=false
The unitils-properties will look the same as before and will contain the database connections
Our dao’s use the EntityManager. To wire it in we use
@Repository
public class PersonDaoJpaImpl {
@PersistenceContext
private EntityManager entityManager;
There is only the spring context left now. In there we need a data source, a dialect, an adapter, an entity manager factory and a transaction manager. And of course your other set-up containing the DAO’s (if you have them)
Combined you get something like this (backend-application-test-context.xml)
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:sdf="http://smals.be/schema/jpa" xmlns:jee="http://www.springframework.org/schema/jee" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee.xsd http://smals.be/schema/jpa http://smals.be/schema/jpa/ttjpa.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd"> <import resource="classpath:spring/backend-application-context.xml" /> <bean id="dataSource" class="org.unitils.database.UnitilsDataSourceFactoryBean" /> <bean id="jpaDialect" class="org.springframework.orm.jpa.vendor.EclipseLinkJpaDialect" /> <bean id="jpaAdapter" class="org.springframework.orm.jpa.vendor.EclipseLinkJpaVendorAdapter"> <property name="databasePlatform" value="org.eclipse.persistence.platform.database.OraclePlatform" /> <property name="showSql" value="true" /> </bean> <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> <property name="persistenceXmlLocation" value="META-INF/persistence-local-test.xml" /> <property name="jpaVendorAdapter" ref="jpaAdapter" /> <property name="dataSource" ref="dataSource" /> </bean> <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"> <property name="entityManagerFactory" ref="entityManagerFactory" /> <property name="jpaDialect" ref="jpaDialect" /> <property name="dataSource" ref="dataSource" /> </bean> </beans>
We import the ‘real’ application context and overwrite the datasource and the entityManagerFactory. So make sure these have the same ID as in the real applicationContext
Your unit test set-up should look like this now
@DataSet
@RunWith(UnitilsJUnit4TestClassRunner.class)
@SpringApplicationContext("backend-application-test-context.xml")
public class PersonDaoJpaImplTest{
@SpringBeanByType
private PersonDao personDao;
@Test
public void testPersist() throws Exception{
....
}
When testing something that fails you have to specify a rollback. The Transactional annotation is the unitils one, not the spring one!
@Test(expected=Exception.class)
@Transactional(TransactionMode.DISABLED)
public void readFailureTest() {
...
}

Posted in 