Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

Platform Details:

Grails-2.3.6 Windows 7 64 bit. JDK v6.

like image 349
Alex Avatar asked Jun 02 '14 16:06

Alex


People also ask

Why do integration tests fail?

For instance, integration tests could fail due to a lost connection with the database. Or perhaps you're using the same environment for both testing and development; in that case, the developers may push new code without tests, causing the test environment to collapse.

What is the major problem during integration testing?

The most common problem I see with integration testing is that most attempts at integration testing do not recognize that people “using” the system have different expectations of the system, and will use the “integrations” differently depending on those expectations and their business needs.

When and where do you use @transactional in testing?

@Transactional spans the transaction for entire test method, so if you use some dao (like in your case) that transaction will be rolledback also, however if some method uses transaction propagation type other than REQUIRED , for example REQUIRED_NEW , call to db can be performed anyway, because REQUIRED_NEW suspends ...

What annotation is used on an integration test method to run it in a transaction?

@Transaction annotation for integration testing in Spring Boot.


1 Answers

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). So, the first time it tries to commit a transaction, it will see this and give the UnexpectedRollbackException you indicated.

I got around this by putting the following in the setUp() of the test that was marked as non-transactional:

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

    SessionHolder sessionHolder = TransactionSynchronizationManager.getResource(sessionFactory)

    if (sessionHolder) {
         sessionHolder.clear()
    }
}
like image 103
Joe Avatar answered Sep 20 '22 12:09

Joe