Integration test does not work with other integration tests that support the transaction

I am having a problem with an integration test that checks multiple services. I had to disable the transaction in order to get the test to work without any transactional runtime errors. The integration test works fine when you run it yourself, but when working with other tests that include a transaction, this runtime error is created:

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 came to the conclusion that the reason the runtime occurs is related to other integration tests that use transactions, since I tested this by successfully completing all the tests that were disabled by the transaction; and was unsuccessful when starting a test using a single integration test with a transaction included.

How can I mix transactional and non-transactional integration tests in Grails?

Platform Details:

Grails-2.3.6 Windows 7 64 bit. JDK v6.

+6
source share
2 answers

Connect to 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 enabled transaction, it will find the SessionHolder associated with the thread with rollbackOnly set to true (since the previous test rollback). So, the first time he tries to commit a transaction, he will see this and throw an UnexpectedRollbackException .

I got around this by putting the following in setUp () of a 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() } } 
+3
source

In integration tests, the following

  • start a transaction
  • run test
  • rollback transaction

in the general case, this will work and reset the database state to the state before the test. But if your test logic will process transactions in a certain way, you will have problems. One example would be to create your own transaction inside test code with propagation = REQUIRES_NEW. Everything you did in this transaction cannot be discarded by the testing logic.

Typically, this code violates the independence between the tests. The only really safe way is to start each test with empty db and insert what you need ...

0
source

Source: https://habr.com/ru/post/970196/


All Articles