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
}
}
}