Вопрос

Я использую TestNG для тестирования модулей Spring на постоянство (JPA+Hibernate), используя AbstractTransactionalTestNGSpringContextTests в качестве базового класса.Все важные части @Autowired, @TransactionConfiguration, @Transactional работают нормально.

Проблема возникает, когда я пытаюсь запустить тест в параллельных потоках с аннотацией threadPoolSize=x, invoctionCount=y TestNG.

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)

...Кто-нибудь сталкивался с этой проблемой?

Вот код:

@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);
    ...
}
...

Обновлять: Кажется, что AbstractTransactionalTestNGSpringContextTests поддерживает транзакцию только для основного потока, когда все остальные тестовые потоки не получают свой собственный экземпляр транзакции.Единственный способ решить эту проблему — расширить AbstractTestNGSpringContextTests и поддерживать транзакцию программно (вместо аннотации @Transactional) для каждого метода (т. е.с 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
        }
    }
}
Это было полезно?

Решение

Транзакция должна быть запущена в том же потоке, вот более подробная информация:

Spring3/Hibernate3/TestNG:некоторые тесты выдают LazyInitializationException, некоторые нет

Другие советы

Вам не кажется, что это скорее связано с тем, что org.springframework.test.context.TestContextManager не является потокобезопасным (см. https://jira.springsource.org/browse/SPR-5863)?

Я столкнулся с той же проблемой, когда хотел параллельно запустить тесты Transactional TestNG, и вы можете видеть, что Spring на самом деле пытается привязать транзакцию к правильному потоку.

Однако это происходит случайно с такими ошибками.Я расширил AbstractTransactionalTestNGSpringContextTests с помощью:

@Override
@BeforeMethod(alwaysRun = true)
protected synchronized void springTestContextBeforeTestMethod(
        Method testMethod) throws Exception {
    super.springTestContextBeforeTestMethod(testMethod);
}

@Override
@AfterMethod(alwaysRun = true)
protected synchronized void springTestContextAfterTestMethod(
        Method testMethod) throws Exception {
    super.springTestContextAfterTestMethod(testMethod);
}

(ключ - синхронизированный...)

и теперь он работает как шарм.Я не могу дождаться Spring 3.2, чтобы его можно было полностью парализовать!

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top