views:

588

answers:

1

I am using TestNG to test persistence Spring modules (JPA+Hibernate) using AbstractTransactionalTestNGSpringContextTests as a base class. All important parts @Autowired, @TransactionConfiguration, @Transactional work just fine.

The problem comes when I am trying to run test in parallel threads with threadPoolSize=x, invocationCount=y TestNG annotation.

WARNING: Caught exception while allowing TestExecutionListener [org.springframework.test.context.transaction.TransactionalTestExecutionListener@174202a] 
to process 'before' execution of test method [testCreate()] for test instance [DaoTest] java.lang.IllegalStateException:
Cannot start new transaction without ending existing transaction: Invoke endTransaction() before startNewTransaction().
at org.springframework.test.context.transaction.TransactionalTestExecutionListener.beforeTestMethod(TransactionalTestExecutionListener.java:123)
at org.springframework.test.context.TestContextManager.beforeTestMethod(TestContextManager.java:374)
at org.springframework.test.context.testng.AbstractTestNGSpringContextTests.springTestContextBeforeTestMethod(AbstractTestNGSpringContextTests.java:146)

... Has anybody faced this problem?

Here is the code:

@TransactionConfiguration(defaultRollback = false)
@ContextConfiguration(locations = { "/META-INF/app.xml" })
public class DaoTest extends AbstractTransactionalTestNGSpringContextTests {

@Autowired
private DaoMgr dm;

@Test(threadPoolSize=5, invocationCount=10)
public void testCreate() {
    ...
    dao.persist(o);
    ...
}
...

Update: It seems that AbstractTransactionalTestNGSpringContextTests maintains transaction only for main thread when all other test threads don't get their own transaction instance. The only way to solve that is to extend AbstractTestNGSpringContextTests and maintain transaction programmatically (instead of @Transactional annotation) per each method (i.e. with TransactionTemplate):

@Test(threadPoolSize=5, invocationCount=10)
public void testMethod() {
    new TransactionTemplate(txManager).execute(new TransactionCallbackWithoutResult() {
        @Override
        protected void doInTransactionWithoutResult(TransactionStatus status) {
            // transactional test logic goes here
        }
    }
}
+1  A: 

The transaction needs to be started in the same thread, here are more details:

http://stackoverflow.com/questions/1571017/spring3-hibernate3-testng-some-tests-give-lazyinitializationexception-some-don

Cedric Beust