Как откат вложенных транзакций с распространением.Требуется новое в интеграционных тестах
у меня есть несколько интеграционных тестов для различных служб, которые расширяют следующий базовый класс:
@ContextConfiguration(locations="classpath:applicationContext-test.xml")
@TransactionConfiguration(transactionManager="txManager", defaultRollback=true)
@Transactional
public abstract class IntegrationTestBase extends AbstractTransactionalJUnit4SpringContextTests
{
//Some setup, filling test data to a HSQLDB-database etc
}
в большинстве случаев это работает отлично, но у меня есть класс, который имеет сделок определен с propagation=Propagation.REQUIRES_NEW
. Кажется, эти транзакции не откатываются (потому что они являются вложенными транзакциями и, по-видимому, фиксируются внутри "внешней" транзакции?). "Внешняя" транзакция (уровень тестового случая) откатывается, по крайней мере, в соответствии с журналами тестов. Зафиксированные транзакции испортите некоторые более поздние тесты, потому что они изменили тестовые данные.
Я могу обойти это, заставляя тест повторно создавать и повторно заполнять базу данных между тестами, но мой вопрос в том, это ожидаемое поведение или я делаю что-то неправильно в своих тестах? Можно ли принудительно откатить вложенную транзакцию из кода тестирования?
2 ответов
это ожидаемое поведение и является одной из основных причин использования REQUIRES_NEW :
- иметь возможность откатить новую транзакцию, но зафиксировать внешнюю
- быть в состоянии совершить новую транзакцию, но откат внешнего
повторное заполнение базы данных между тестами, вероятно, является лучшим решением, и я бы использовал это решение для всех тестов: это позволяет тестам проверять, что все работает правильно, включая фиксацию (которая может не из-за промывки, отложенных ограничений и т. д.).
но если вы действительно хотите откатить транзакцию, решением было бы добавить логический аргумент rollbackAtTheEnd
к вашей службе и откат транзакции, если этот аргумент верен.
я добавил комментарий к Spring улучшение билета об этом. Я тоже скопирую здесь:
я работал над этой проблемой, Преобразуя все методы службы, которые были декларативно настроены так
@Transactional(propagation = REQUIRES_NEW)
public Object doSmth() {
// doSmthThatRequiresNewTx
}
использовать TransactionTemplate
вместо:
private TransactionTemplate transactionTemplate;
public Object doSmth() {
return transactionTemplate.execute(new TransactionCallback<Object>() {
@Override
public Object doInTransaction(TransactionStatus status) {
// doSmthThatRequiresNewTx
}
});
}
под тестами настраиваю transactionTemplate
поведение животных будут PROPAGATION_REQUIRED
, в реальном приложении я настраиваю transactionTemplate
поведение распространения должно быть PROPAGATION_REQUIRES_NEW
. Работает, как и ожидалось. Ограничение этот обходной путь заключается в том, что при тестировании невозможно утверждать, что внутренняя транзакция не откат в исключительном сценарии.
другим решением было бы явно удалить все doSmth()
на базу в @AfterTransaction
метод тестирования. Этот "delete" SQL будет запущен в новой транзакции, так как в противном случае его результаты будут регулярно откатываться Spring's TransactionConfiguration
поведение по умолчанию.