使用测试代码很难验证事务内的休眠更新查询

mat*_*uck 5 testing spring hibernate jpa

我在尝试为使用直接 sql 查询在单个事务中更新数据库的 hibernate DAO 编写测试代码的验证部分时遇到了相当大的挫折。

背景:

  • 将 Hibernate 4.1 与 Spring 4 结合使用
  • 事务边界通过注释控制@Transactional/JpaTransactionManager
  • 我们大多数情况下只是使用 hibernate 作为 JPA 实现,并避免大多数 hibernate 特定的事情;即我们不Session直接与对象交互。

情况:我有一个使用 NamedQuery 执行直接 SQL/HQL 更新的 DAO。以这种方式执行更新(而不是调用entityManager.persist)的主要驱动程序是分离对象的问题。我不想重新获取对象只是为了坚持保存我对它的更改。对象被分离的原因是因为它被缓存了。

我想编写一个单元测试来调用该 DAO 的 update 方法,然后调用 DAO 的 find 方法从数据库中拉回新鲜的对象,以验证更改是否正确。另一个问题是我希望这个单元测试在事务(即 的子类)中运行,AbstractTransactionalTestNGSpringContextTests以便回滚更改并保持状态干净以供下一个测试。

问题的关键:当我在执行更新后调用 DAO 上的 find 方法时,Hibernate 显然对已发生的更改一无所知。我认为这是由于一些缓存或休眠中的某些原因导致它由于某种原因无法获取这些更改。我试图寻找这个缓存并使其无效;到目前为止还没有成功。

例子:

@Test
public void testUpdate() {
    SomeUser obj = makeSomeUser("joe");

    // update the name using a NamedQuery; does not call `persist`
    dao.updateName(obj.getId(), "bob"); 

    SomeUser found = dao.find(obj.getId());
    // This verification fails, it finds "joe" still
    assertEquals(found.getName(), "bob"); 
}
Run Code Online (Sandbox Code Playgroud)

别处...

public void updateName(long id, String newName) {
    Query query = entityManager.createQuery("UPDATE USERS set NAME = :name WHERE id = :id");
    query.setParameter("name", newName);
    query.setParameter("id", id);
    query.executeUpdate();
}
Run Code Online (Sandbox Code Playgroud)

我过去解决这个问题的唯一方法是:

  1. 不要在事务中运行测试,然后再执行手动清理。我真的很想避免这种情况,因为我认为这是不好的做法。
  2. 用于entityManger.createNativeQuery执行能够检测更新的更改的验证步骤。我想避免这种情况,因为它不一致并且最终会为了测试而重复代码。我想在测试中使用与我们在代码库的其余部分中所做的相同的查找代码......

我刚刚错过了一个简单的答案吗?我是否可能以非休眠友好的方式做事?有没有更好的方法来测试 hibernate DAO?

Vae*_*lyr -2

首先。为什么要费心测试 DAO?您应该只专注于通过具有一些实际价值和反馈的适当服务进行集成测试。如果您在专用服务之外进行操作,则不会进行任何交易。

这个updateName功能很奇怪。在 JPA 中对实体执行更新时,在大多数情况下,我们会传入更新的实体并获取为要更新的实体设置的新值。makeSomeUser()该方法实际上做了什么?它是否持久化实体?提供更多代码。如果你想测试更新,你需要有一个持久化实体,你必须知道你要更新什么,通过获取id,根据该id在数据库中执行查找,如果返回匹配的实体则执行更新操作返回的实体。事务结束时,所有更改都将被保留。您的测试方法在这里是错误的。

  • (啊!)我之所以想一开始就测试 DAO,是因为它们里面有代码……我想严格测试 SQL 语句,以确保它们完全按照我希望的方式做,这种方式在更高的集成测试级别上更难做到。即使我说我正在测试服务对象/管理器而不是实际的 DAO,它仍然是在单个事务中,并且我遇到了相同的情况。 (2认同)