在尝试为使用直接 sql 查询在单个事务中更新数据库的 hibernate DAO 编写测试代码的验证部分时,我遇到了很多挫折。
背景:
- 在 Spring 4 中使用 Hibernate 4.1
- 事务边界通过
@Transactional
注解/JpaTransactionManager
控制 - 在大多数情况下,我们只是将 hibernate 用作 JPA 实现,并避免大多数特定于 hibernate 的东西;也就是说,我们永远不会直接与
Session
对象进行交互。
情况:我有一个使用 NamedQuery 执行直接 SQL/HQL 更新的 DAO。以这种方式(与调用 entityManager.persist
相对)执行更新的主要驱动因素是分离对象的问题。我不想为了保存我对它所做的更改而重新获取对象。对象被分离的原因是因为它被缓存了。
我想编写一个调用此 DAO 的更新方法的单元测试,然后调用 DAO 的查找方法从数据库中拉回新鲜的对象以验证所做的更改是否正确。另一个问题是,我希望此单元测试在事务(即 AbstractTransactionalTestNGSpringContextTests
的子类)中运行,以便回滚更改并为下一次测试保留干净的状态。
问题的关键:当我在执行更新后调用 DAO 上的查找方法时,Hibernate 显然对发生的更改一无所知。我认为这是由于某些缓存或 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");
}
其他地方...
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();
}
我过去解决这个问题的唯一方法是:
- 不要在事务中运行测试,然后再执行手动清理。我真的很想避免这种情况,因为我认为这是不好的做法。
- 使用
entityManger.createNativeQuery
执行能够检测更新更改的验证步骤。我想避免这种情况,因为它不一致并且最终只是为了测试而复制代码。我想在测试中使用与我们在代码库的其余部分中相同的查找代码...
我刚刚错过了一个简单的答案吗?我是否可能以一种非 hibernate 友好的方式做事?有没有更好的方法来测试 hibernate DAO?
最佳答案
如果您将存储库集成测试视为在您的体系结构中与您通常将存储库注入(inject)的服务占据相同的位置,这可能会有所帮助。考虑到这一点,您可以在测试中放置 @Transactional
注释(来自 spring-tx),以划定事务边界。这允许测试插入/更新测试数据,并在事务期间检查数据库,并在测试结束时事务回滚时自动清除所有这些(它将)。
在我正在处理的系统中,我们所有的集成测试都是使用这种策略编写的。他们都有这种形式:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("/integration-test-context.xml")
@Transactional
public class ThingRepositoryIT {...}
我们总是从配置我们需要使用的数据的@Before
开始:
@Autowired
private JdbcTemplate jdbcTemplate;
获取可以运行创建测试数据的运行脚本的 jdbc 模板的句柄。
此外,我们经常需要在测试中的 hibernate session 上调用 flush()
,以确保在测试之前 hibernate 已将其缓存数据写入数据库。
关于spring - 难以使用测试代码验证事务内的 hibernate 更新查询,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26105773/