简体   繁体   English

与其他启用了事务的集成测试一起运行时,集成测试失败

[英]An integration test fails when running with other integration tests which have transactional enabled

I am having a problem with an integration test which tests several services. 我遇到了一个测试多个服务的集成测试的问题。 I had to disable transactional to get the test working without any transactional related runtime errors. 我不得不禁用事务以使测试工作而没有任何与事务相关的运行时错误。 The integration test works fine when running it on its own but when running with other tests, which have transactional enabled, it creates this runtime error: 集成测试在单独运行时工作正常但在与其他启用了事务的测试一起运行时,会产生此运行时错误:

Running 48 integration tests... 43 of 48
Failure:  Tests the happy case flow of MyService.(MyServiceSpec)
org.springframework.transaction.HeuristicCompletionException: Heuristic completion: outcome state is rolled back; nested exception is org.springframework.transaction.UnexpectedRollbackException: Transaction rolled back because it has bee
n marked as rollback-only
Caused by: org.springframework.transaction.UnexpectedRollbackException: Transaction rolled back because it has been marked as rollback-only
        ... 4 more
Completed 43 integration tests, 1 failed in 0m 32s

I have concluded that the reason the runtime occurs is because of the other integration tests which use transactions, as I tested this by successfully running all tests which have transactional disabled; 我得出结论,运行时发生的原因是因为使用事务的其他集成测试,因为我通过成功运行所有禁用事务的测试来测试它; and was unsuccessful when running the test with a single integration test with transactional enabled. 在使用事务启用的单个集成测试运行测试时失败。

How can I mix transactional and non-transactional integration tests in Grails? 如何在Grails中混合事务和非事务集成测试?

Platform Details: 平台详情:

Grails-2.3.6 Windows 7 64 bit. Grails-2.3.6 Windows 7 64位。 JDK v6. JDK v6。

Ran into this with Grails 2.4.3 and after a bunch of debugging saw that in org.springframework.orm.hiberante4.HibernateTransactionManager.doGetTransaction() it calls TransactionSynchronizationManager.getResource(getSessionFactory()) and if there were other tests with transactional enabled then it will find a thread-bound SessionHolder with rollbackOnly set to true (since the previous test rolled back). 使用Grails 2.4.3进入这个并且在一堆调试之后看到org.springframework.orm.hiberante4.HibernateTransactionManager.doGetTransaction()它调用TransactionSynchronizationManager.getResource(getSessionFactory())并且如果有其他测试启用了事务,那么它会找到一个线程绑定的SessionHolder,其rollbackOnly设置为true(因为之前的测试已回滚)。 So, the first time it tries to commit a transaction, it will see this and give the UnexpectedRollbackException you indicated. 因此,第一次尝试提交事务时,它会看到这个并给出你指出的UnexpectedRollbackException

I got around this by putting the following in the setUp() of the test that was marked as non-transactional: 通过将以下内容放在标记为非事务性的测试的setUp()中,我解决了这个问题:

Holders.grailsApplication.mainContext.getBeansOfType(SessionFactory.class).each { beanName, sessionFactory ->

    SessionHolder sessionHolder = TransactionSynchronizationManager.getResource(sessionFactory)

    if (sessionHolder) {
         sessionHolder.clear()
    }
}

Integration tests will do the following 集成测试将执行以下操作

  • start transaction 开始交易
  • run test 运行测试
  • rollback transaction 回滚事务

in general this will work and reset the database state to the state before the test. 通常,这将工作并将数据库状态重置为测试之前的状态。 But if your test logic will treat transactions in a specific way you will run into problems. 但是,如果您的测试逻辑将以特定方式处理事务,那么您将遇到问题。 One example would be creating your own transaction inside the test code with propagation=REQUIRES_NEW. 一个例子是使用propagation = REQUIRES_NEW在测试代码中创建自己的事务。 Whatever you did in that transaction can not be rolled back by the test logic. 无论您在该事务中执行了什么操作,都无法通过测试逻辑回滚。

Usually code like that will break the independence between tests. 通常这样的代码会打破测试之间的独立性。 The only really safe way is to have each test start with an empty db and insert what is needed ... 唯一真正安全的方法是让每个测试以空数据库开始并插入所需的内容......

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM