如何在集成测试中使用Propagation.REQUIRES_NEW回滚嵌套事务

esa*_*saj 20 spring integration-testing hibernate transactions rollback

我对扩展以下基类的各种服务进行了多次集成测试:

@ContextConfiguration(locations="classpath:applicationContext-test.xml")
@TransactionConfiguration(transactionManager="txManager", defaultRollback=true)
@Transactional
public abstract class IntegrationTestBase extends AbstractTransactionalJUnit4SpringContextTests
{
    //Some setup, filling test data to a HSQLDB-database etc
}
Run Code Online (Sandbox Code Playgroud)

对于大多数情况,这工作正常,但我有一个服务类,其中定义了事务propagation=Propagation.REQUIRES_NEW.似乎这些事务没有回滚(因为它们是嵌套事务并且显然在"外部"事务中提交?).回滚"外部"(测试用例级别)事务,至少根据测试日志.提交的事务会使一些后续测试陷入混乱,因为它们已经更改了测试数据.

我可以通过强制测试在测试之间重新创建和重新填充数据库来解决这个问题,但我的问题是,这是预期的行为还是我在测试中做错了什么?是否可以强制嵌套事务从测试代码回滚?

JB *_*zet 12

这是预期的行为,也是使用REQUIRES_NEW的主要原因之一:

  • 能够回滚新事务,但提交外部事务
  • 能够提交新事务,但回滚外部事务

在测试之间重新填充数据库可能是最好的解决方案,我会将此解决方案用于所有测试:这允许测试检查一切是否正常,包括提交(由于刷新,延迟约束等可能会失败) ).

但是你真的想要回滚事务,解决方案是rollbackAtTheEnd为你的服务添加一个布尔参数,如果这个参数为真,则回滚事务.

  • 我希望有一个更好的解决方案,因为每次集成测试需要花费大量时间来重新创建数据库. (2认同)

par*_*ier 5

我在这上面添加了对Spring 改进票的评论.我也会在这里复制它:

我通过转换所有声明性设置的服务方法解决了这个问题

@Transactional(propagation = REQUIRES_NEW)
public Object doSmth() {
  // doSmthThatRequiresNewTx
}
Run Code Online (Sandbox Code Playgroud)

改为使用TransactionTemplate:

private TransactionTemplate transactionTemplate;

public Object doSmth() {
  return transactionTemplate.execute(new TransactionCallback<Object>() {
            @Override
            public Object doInTransaction(TransactionStatus status) {
                // doSmthThatRequiresNewTx
            }
        });
  }
Run Code Online (Sandbox Code Playgroud)

在测试中我配置transactionTemplate的传播行为是PROPAGATION_REQUIRED,在真实应用程序下我配置transactionTemplate的传播行为PROPAGATION_REQUIRES_NEW.它按预期工作.此变通办法的局限性在于,在测试中,不可能断言内部事务在特殊情况下回滚的事实.

另一个解决方案是显式删除测试方法中doSmth()数据库中的所有内容@AfterTransaction."删除"SQL将在新事务中运行,因为其结果将通过Spring的TransactionConfiguration默认行为以常规方式回滚.