使用Entity Manager的Spring junit测试不会在H2文件系统数据库中插入数据

时间:2014-08-07 15:56:39

标签: java spring hibernate junit h2

首先我的设置:

  • JUnit版本:4.11
  • H2版本:1.3.174
  • 春季版:4.0.5.RELEASE
  • Hibernate版本:4.1.0.Final

一点背景:

我有一个部署在Tomcat网络服务器上的REST Web服务,下面有一个h2数据库。我有一个没有任何POST / PUT方法的REST服务。在为其编写集成测试时,我使用H2控制台手动添加了数据库中的条目,并将h2文件放在服务器上。最后,我的集成测试调用REST服务,并返回在DB中手动注入的数据,测试成功。这是不可维护的,为每个测试注入我需要的数据会很棒(这种方法可以用于以后的其他集成测试......)。目标是将数据注入与Tomcat上部署的应用程序使用的数据库相同的数据库。

我认为这很容易,我编写了一个集成测试,重用了服务器端使用的相同应用程序上下文:

 <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>

数据库url在属性fil:

中定义
database.url=jdbc:h2:file:${healthdata.working.dir}/database/database-catalogue;AUTO_SERVER=true

然后我将EntityManager注释为我的PersistenceContext并编写了一个简单的单元测试:

@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);
    }
}

此测试运行良好!但是,当我使用EntityManager刷新数据并且连接到我的H2文件系统数据库后放置断点时,没有注入任何内容!

现在我在想。使用Spring NEVER的JUnit实际上是否将数据保存在数据库中并将其保存在内存中是否正常?有没有办法坚持它,所以我可以用它来预先填充数据库以进行集成测试。

现在我有一个解决方法,使用旧的JDBC存储我的数据,但它很脏,我认为它应该使用Spring,最重要的是我想了解为什么数据不是使用Spring的EntityManager持久化...

2 个答案:

答案 0 :(得分:7)

正在进行的是JPA如何工作以及Spring在运行事务测试时所做的工作。

首先,当JPA中持有实体时,JPA并不意味着数据实际上是持久存储到数据库中的。通常,当前事务提交时,或者当您刷新实体管理器时,数据将被推送到数据库。 查看this通过简单的谷歌搜索找到的许多答案。

其次,当Spring运行使用@Transactional注释的测试时,默认情况下它将在测试完成时回滚事务。检查许多类似问题的this。要覆盖该默认行为,您需要使用@Rollback(false)

当您使用JDBC时,数据会写入文件,因为您正在运行Spring为测试创建的事务之外的语句,因此默认回滚没有要还原的数据。

答案 1 :(得分:1)

在班级或方法级别添加@Commit。查看this

  

当声明为类级别注释时,@ Commit定义测试类层次结构中所有测试方法的默认提交语义。当声明为方法级注释时,@ Commit定义特定测试方法的提交语义,可能会覆盖类级别的默认提交或回滚语义。