JPA - 如何在单元测试之间截断表

时间:2010-10-13 16:19:04

标签: unit-testing jpa jpa-2.0 dbunit

我希望在每个测试用例之后清理数据库而不回滚事务。我尝试过DBUnit的DatabaseOperation.DELETE_ALL,但如果删除违反了外键约束,它就不起作用。我知道我可以禁用外键检查,但这也会禁用对测试的检查(我想阻止)。

我正在使用JUnit 4,JPA 2.0(Eclipselink)和Derby的内存数据库。有什么想法吗?

谢谢, 西奥

8 个答案:

答案 0 :(得分:18)

最简单的方法是使用nativeQuery jpa方法。

@After
public void cleanup() {
    EntityManager em = entityManagerFactory.createEntityManager();
    em.getTransaction().begin();
    em.createNativeQuery("truncate table person").executeUpdate();
    em.createNativeQuery("truncate table preferences").executeUpdate();
    em.getTransaction().commit();
}

答案 1 :(得分:4)

简单:在每次测试之前,启动一个新事务,然后在测试之后回滚。这将为您提供与之前相同的数据库。

确保测试不会创建新的交易;而是重用现有的。

答案 2 :(得分:2)

是的,交易中测试会让您的生活更轻松,但如果交易是您的事情,那么您需要在清理期间(@After)实施补偿交易。这听起来很费劲,但如果得到适当的处理,你最终可能会得到一组辅助方法(在测试中)来补偿(清理)在@Before和测试期间累积的数据(使用JPA或直接JDBC - 无论什么都有意义)。

例如,如果您在测试期间使用JPA并在实体上调用create方法,则可以使用(如果您喜欢使用AOP或仅使用像我们这样的帮助测试方法),则可以使用所有测试中的模式:

  1. 跟踪测试期间创建的所有实体的ID
  2. 按照创建的顺序累积它们
  3. @After
  4. 中的相反顺序重播实体删除这些实体

答案 3 :(得分:1)

我有点困惑,因为DBUnit会在每次测试之前将数据库重新初始化为已知状态。

他们recommend as a best practice也不会在测试后清理或以其他方式更改数据。

因此,如果是清理工作,你需要为下一次测试准备数据库,我不会打扰。

答案 4 :(得分:0)

我的设置非常相似:它是Derby(嵌入式)+ OpenJPA 1.2.2 + DBUnit。以下是我处理当前任务的集成测试的方法:在每个@Before方法中,我运行3个脚本:

  1. 删除数据库 - 删除所有表的SQL脚本。
  2. 创建数据库 - 重新创建数据库的SQL脚本。
  3. 用于填充数据的特定于测试的数据库单元XML脚本。
  4. 我的数据库只有12个表,测试数据集也不是很大 - 约50个记录。每个脚本运行大约需要500毫秒,并且在添加或修改表时手动维护它们。

    这种方法可能不建议用于测试大型数据库,也许它甚至不能被视为小型数据库的良好实践;但是,与在@After方法中回滚事务相比,它有一个重要优势:您可以实际检测提交时发生的情况(如持久化分离实体或乐观锁异常)。

答案 5 :(得分:0)

晚了好,从不...... 我遇到了同样的问题,并提出了一个非常简单的解决方案:

  1. 设置属性" ... database.action "价值" drop-and-create "在你的persistence-unit config
  2. 在每次测试后关闭实体经理和实体经理工厂
  3. 的persistence.xml

        <persistence-unit name="Mapping4" transaction-type="RESOURCE_LOCAL" >
        <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
        <class>...</class>
        <class>...</class>
    
        <properties>
            ...
            <property name="javax.persistence.schema-generation.database.action" value="drop-and-create" />
            ...
        </properties>
    </persistence-unit>
    

    单元测试:

    ...
    @Before
    public void setup() {
        factory = Persistence.createEntityManagerFactory(PERSISTENCE_UNIT_NAME);
        entityManager = factory.createEntityManager();
    }
    
    
    @After
    public void tearDown() {
        entityManager.clear();
        entityManager.close();
        factory.close();
    }
    

    ...

答案 6 :(得分:0)

每次运行后,我都会删除数据库文件:

boolean deleted = Files.deleteIfExists(Paths.get("pathToDbFile"));

有点脏但是对我有用。 问候

答案 7 :(得分:0)

选项1:您可以在截断表之前禁用外键检查,并在截断后再次启用它们。您仍将以这种方式在测试中进行检查。

选项2::当最后一个连接关闭时,H2数据库将破坏内存数据库。我猜Derby DB支持类似的功能,或者您可以切换到H2。

另请参见:我在以下相关问题中使用Hibernate编写了一段代码,在每次测试之前截断表:https://stackoverflow.com/a/63747005/471214