First my setup:
- JUnit version: 4.11
- H2 version: 1.3.174
- Spring version: 4.0.5.RELEASE
- Hibernate version: 4.1.0.Final
A little context:
I have a REST web service that is deployed on a Tomcat webserver and that has a h2 database underneath. I have a REST service that doesn't have any POST/PUT methods. When writing an integration test for it, I manually added the entries in the DB using the H2 console and placed the h2-file on the server. Finally my integration test calls the REST service and the data I manually injected in the DB is returned and the test succeeds. This is not maintainable and it would be great to inject for every test the data I need (this approach can be used for other integration tests later...). The goal is to inject data into the same database as the application deployed on Tomcat is using.
I thought it would be very easy and I wrote an integration test reusing the same application context that is used on the server side:
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="org.h2.Driver" />
<property name="url" value="${database.url}" />
<property name="username" value="" />
<property name="password" value="" />
</bean>
<bean id="emf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="packagesToScan" value="be.wiv_isp.healthdata.catalogue.domain" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
</property>
<property name="jpaProperties">
<props>
<prop key="hibernate.hbm2ddl.auto">update</prop>
<prop key="hibernate.dialect">org.hibernate.dialect.H2Dialect</prop>
</props>
</property>
</bean>
<bean id="jpaVendorAdaptor" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
<tx:annotation-driven transaction-manager="transactionManager"/>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="emf" />
</bean>
where the database url is defined in a properties fil:
database.url=jdbc:h2:file:${healthdata.working.dir}/database/database-catalogue;AUTO_SERVER=true
Then I annotated the EntityManager as being my PersistenceContext and wrote a simple unit test:
@Transactional
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(value = {"classpath:/applicationContext-it-test.xml"})
public class H2Test {
@PersistenceContext
private javax.persistence.EntityManager em;
DataCollectionDefinition dcd = new DataCollectionDefinitionBuilder()
.withId(Long.valueOf(1))
.build();
@Before
public void init() {
em.persist(dcd);
em.flush();
em.clear();
}
@Test
public void testGet() {
DataCollectionDefinition found = em.find(DataCollectionDefinition.class, 1);
Assert.assertEquals(found, dcd);
}
}
This test runs fine! However when I put a breakpoint after the data is flushed using the EntityManager and I connect to my H2 filesystem database, nothing is injected!
Now I was wondering. Is it normal that JUnit using Spring NEVER actually persists the data in the database and keeps it somewhere in memory? And is there a way to persist it anyway, so I could use it for prefilling of the database for my integration tests.
For now I have a workaround storing my data using good old JDBC, but it's dirty and I think it should work using Spring and above all I would like to understand why the data is not persisted using the EntityManager of Spring...