【问题标题】:Non-transactional unit test with spring and hibernate使用 spring 和 hibernate 进行非事务性单元测试
【发布时间】:2012-11-21 09:35:13
【问题描述】:

您好,我有一个单元测试应该测试一个 cronjob

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "file:WebContent/WEB-INF/applicationContext.xml" })
@TransactionConfiguration(transactionManager = "hibernateTransactionManager")
@Transactional
public class cronTest {}

但由于事务的原因,cronjob 看不到测试的数据。但是当我删除@Transactional Hibernate 时说:

org.hibernate.HibernateException: No Session found for current thread

当我自己提交时

sessionFactory.getCurrentSession().getTransaction().commit();
sessionFactory.getCurrentSession().beginTransaction();

测试最终失败

org.springframework.transaction.TransactionSystemException: Could not commit Hibernate transaction; nested exception is org.hibernate.TransactionException: Transaction not successfully started

如何在没有事务的情况下进行单元测试?

测试做了类似的事情:

    userDao.clear();
    loadeduser = userService.getUserById(createUser.getUserID());
    assertTrue(loadeduser.getAuthoritiesEntities().contains(adminRole));
    assertTrue(loadeduser.getAuthoritiesEntities().contains(userRole));

    // Wait for auto unsign
    TestUtils.sleep(10000);

    userDao.clear();
    loadeduser = userService.getUserById(createUser.getUserID());
    assertFalse(loadeduser.getAuthoritiesEntities().contains(adminRole));
    assertTrue(loadeduser.getAuthoritiesEntities().contains(userRole));

它检查过期角色的自动取消签名是否有效,quartz 作业每 5 秒运行一次

【问题讨论】:

  • 可以多加些crontTest()的内容吗?我想看看被测对象的方法调用,以及 sessionFactory 方法的位置。

标签: spring hibernate unit-testing transactions


【解决方案1】:

通常我建议对可在单个事务中测试的代码使用单元测试,并使用集成测试(启动整个系统并执行您想要测试的顺序)来测试多事务行为。

但要回答这个问题:解决此问题的一种方法是像您所做的那样从测试方法中删除@Transaction,但不是直接使测试方法控制事务,而是允许您正在测试的方法开始/提交他们自己的交易(他们通常会这样做,对吧?)

例如,我们可能有通过正常 DAO 工作流运行的测试,并且每个 DAO 方法都标记为@Transactional。每个方法都控制自己的事务提交,因此我们可以在单个测试方法中测试多事务行为。该测试可能如下所示:

// no @Transactional here, dao methods are @Transactional
public void testMultiTransactionUpdate() {
    Entity t = dao.getEntity(id);
    t.setProperty("somethingnew");
    dao.update(t);
    Entity t2 = dao.getEntity(id);
    Assert.assertEquals(t1.getProperty(), t2.getProperty());
}

需要注意的一点是,如果您提交的是内存数据库(如 HSQLDB),您在一次测试中所做的更改将不会自动回滚,并且通常对后续测试可见。您必须在测试结束时手动撤消所有更改,或确保您的测试数据不会干扰其他不太容易的测试。这就是为什么我会谨慎使用这种技术。

【讨论】:

  • 嗨,我需要这样的测试,因为我想确保石英配置正确。我正在调用一个事务性服务,但在测试中没有事务性我得到“org.hibernate.HibernateException: No Session found for current thread”
  • 您可以将测试代码添加到您的问题中吗?您的测试中的某些内容正在调用需要打开会话的代码,而我看不到那是什么。通常,在您的服务方法上小心放置 @Transactional 就足够了。
  • 另外,您可以在您的测试中保留 Transactional,并将 defaultRollback=false 添加到您的 TransactionConfiguration,并在 After 注释方法中测试您想要测试的内容。在这种情况下,您可能希望这是班级中唯一的测试。
  • 感谢您提供测试代码。当您从单元测试中删除 @Transactional 时,您还可以包含更多的堆栈跟踪吗?我很好奇你的代码中哪里抛出了异常。更多问题: userDao.clear() 是做什么的? userService.getUserById() 本身是否标记为@Transactional?在从服务返回之前,您是否确保加载用户的权限已完全加载? (虽然如果他们不是我更期待一个 LazyInitializationException)
  • 另外,当您运行手动测试时,您的代码有效吗?确保测试方法中的调用顺序与实时手动测试中的调用顺序相同。同样,测试中的每个方法都应该有自己的事务边界,并且不应该有任何方法调用试图访问当前会话而不控制自己的事务。
猜你喜欢
  • 2019-05-29
  • 2011-11-17
  • 1970-01-01
  • 1970-01-01
  • 2016-11-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多