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

iibxawm4  于 2023-08-06  发布在  其他
关注(0)|答案(9)|浏览(108)

我想在每个测试用例之后清理数据库,而不回滚事务。我尝试了DBUnit的DatabaseOperation.DELETE_ALL,但是如果删除违反外键约束,它就不起作用。我知道我可以禁用外键检查,但这也会禁用测试的检查(我想阻止)。
我使用的是JUnit 4、JPA 2.0(Eclipselink)和Derby的内存数据库。有什么想法吗
谢谢,西奥

2izufjch

2izufjch1#

最简单的方法可能是使用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();
}

字符串

jbose2ul

jbose2ul2#

简单:在每次测试之前,启动一个新事务,在测试之后,将其回滚。这将为您提供与之前相同的数据库。
确保测试不会创建新的事务;而不是重用现有的。

bbuxkriu

bbuxkriu3#

我有点困惑,因为DBUnit会在每次测试之前将数据库重新初始化为已知状态。
他们还建议最好不要在测试后清理或更改数据。
因此,如果您要为下一个测试准备数据库,那么我不会打扰。

kx5bkwkv

kx5bkwkv4#

是的,事务内测试会让你的生活更容易,但是如果事务是你的事情,那么你需要在清理过程中实现补偿事务(在@After中)。这听起来很费力,但如果方法得当,您可能最终会得到一组帮助器方法(在测试中),这些方法可以补偿(清理)在@Before和测试(使用JPA或直接JDBC -任何有意义的方法)期间积累的数据。
例如,如果你使用JPA并在测试期间调用实体上的create方法,你可以在所有测试中使用(如果你喜欢的话使用AOP,或者像我们一样使用助手测试方法)一个模式:
1.跟踪测试期间创建的所有实体的ID
1.将它们按创建的顺序累积起来
1.在@After中以相反的顺序重放这些实体的实体删除

qij5mzcb

qij5mzcb5#

我的设置非常相似:它是Derby(嵌入式)+ OpenJPA 1.2.2 + DBUnit。下面是我如何处理当前任务的集成测试:在每个@Before方法中,我运行3个脚本:
1.删除DB -删除所有表的SQL脚本。

  1. Create DB -一个重新创建它们的SQL脚本。
    1.用于填充数据的特定于测试的DB单元XML脚本。
    我的数据库只有12个表,测试数据集也不是很大,大约有50条记录。每个脚本运行大约需要500毫秒,当添加或修改表时,我手动维护它们。
    这种方法可能不推荐用于测试大型数据库,甚至可能不被认为是小型数据库的良好实践;但是,与回滚@After方法中的事务相比,它有一个重要的优点:你可以实际检测到在提交时发生了什么(比如持久化分离实体或乐观锁异常)。
qyswt5oh

qyswt5oh6#

迟做总比不做好。。我也遇到了同样的问题,并提出了一个非常简单的解决方案:
1.在持久化单元配置中将属性“... database.action”设置为值“drop-and-create
1.每次测试后关闭实体管理器和实体管理器工厂
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();
}


...

s8vozzvw

s8vozzvw7#

我在每次运行后删除DB文件:

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

字符串
有点脏,但对我有用。谨致问候

t5fffqht

t5fffqht8#

**选项一:**可以在截断表前关闭外键检查,截断表后重新开启。您仍然可以通过这种方式检查测试。
**选项2:**H2数据库在最后一次连接关闭时销毁内存数据库。我猜Derby DB支持类似的东西,或者您可以切换到H2。
**另请参阅:**我在一个相关问题中使用Hibernate编写了一段代码,用于在每次测试之前截断表:https://stackoverflow.com/a/63747005/471214

lnlaulya

lnlaulya9#

不是这个问题的正确答案。但这是Google页面的第一个结果,所以这里是Hibernate用户的答案:

import jakarta.persistence.EntityManager;
import org.hibernate.Session;

Session session = entityManager.unwrap(Session.class);
session.getSessionFactory().getSchemaManager().truncateMappedObjects();

字符串
先打电话通知。

相关问题