Интеграционное тестирование в Spring: TestContext Framework, включение и отключение транзакций
Аннотирование метода теста с помощью @Transactional приводит к тому, что тест запускается в транзакции, которая по умолчанию автоматически откатывается после завершения теста. Если тестовый класс аннотируется @Transactional, каждый тестовый метод в этой иерархии классов выполняется внутри транзакции. Методы тестирования, не помеченные @Transactional (на уровне класса или метода), не выполняются в транзакции. Обратите внимание, что @Transactional не поддерживается в методах жизненного цикла теста - например, методы, аннотированные JUnit Jupiter @BeforeAll, @BeforeEach и т.д. Кроме того, тесты, аннотированные @Transactional, но имеющие атрибут propagation, установленный на NOT_SUPPORTED, не выполняются в пределах транзакции.
Поддержка атрибута @Transactional
Атрибут | Поддерживается для транзакций, управляемых тестами |
---|---|
value и transactionManager | да |
propagation | только Propagation.NOT_SUPPORTED и Propagation.NEVER поддерживаются |
isolation | нет |
timeout | нет |
readOnly | нет |
rollbackFor и rollbackForClassName | нет: используйте вместо этого TestTransaction.flagForRollback() |
noRollbackFor и noRollbackForClassName | нет: используйте вместо этого TestTransaction.flagForCommit() |
Методы жизненного цикла на уровне методов - например, методы, аннотированные JUnit Jupiter @BeforeEach или @AfterEach - выполняются в рамках транзакции, управляемой тестом. С другой стороны, методы жизненного цикла уровня набора и уровня класса - например, методы, аннотированные JUnit Jupiter @BeforeAll или @AfterAll, и методы, аннотированные TestNG @BeforeSuite, @AfterSuite, @BeforeClass или @AfterClass - не выполняются внутри транзакции, управляемой тестами.
Если вам нужно запустить код в методе жизненного цикла уровня набора или уровня класса внутри транзакции, вы можете добавить соответствующий PlatformTransactionManager в свой тестовый класс, а затем использовать его с TransactionTemplate для программного управления транзакциями.
Обратите внимание, что AbstractTransactionalJUnit4SpringContextTests и AbstractTransactionalTestNGSpringContextTests предварительно настроены для поддержки транзакций на уровне класса.
В следующем примере демонстрируется общий сценарий написания интеграционного теста для UserRepository на основе Hibernate:
@SpringJUnitConfig(TestConfig.class)
@Transactional
class HibernateUserRepositoryTests {
@Autowired
HibernateUserRepository repository;
@Autowired
SessionFactory sessionFactory;
JdbcTemplate jdbcTemplate;
@Autowired
void setDataSource(DataSource dataSource) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
}
@Test
void createUser() {
// отслеживаем начальное состояние
// в тестовой базе данных:
final int count = countRowsInTable("user");
User user = new User(...);
repository.save(user);
// Ручной flush необходим,
// чтобы избежать ложного срабатывания теста
sessionFactory.getCurrentSession().flush();
assertNumUsers(count + 1);
}
private int countRowsInTable(String tableName) {
return JdbcTestUtils.countRowsInTable(this.jdbcTemplate, tableName);
}
private void assertNumUsers(int expected) {
assertEquals("Number of rows in the [user] table.", expected, countRowsInTable("user"));
}
}
Нет необходимости очищать базу данных после запуска метода createUser(), поскольку любые изменения, внесенные в базу данных, автоматически откатываются TransactionalTestExecutionListener.
Поведение отката и фиксации транзакции
По умолчанию тестовые транзакции автоматически откатываются после завершения теста; однако поведение фиксации и отката транзакции можно настроить декларативно с помощью аннотаций @Commit и @Rollback.
Читайте также:
- Интеграционное тестирование в Spring: TestContext Framework, внедрение зависимостей тестовых приспособлений
- Интеграционное тестирование в Spring: TestContext Framework, тестирование бинов области действия запроса и сеанса
- Интеграционное тестирование в Spring: TestContext Framework, управление транзакциями
Комментарии
Отправить комментарий