Рубрики
Без рубрики

Программные транзакции в рамках Spring TestContext

Краткое и практическое руководство по управлению транзакциями в Spring TestContext.

Автор оригинала: baeldung.

1. введение

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

Однако иногда нам может потребоваться четкий контроль над границами транзакций.

В этой статье мы увидим как программно взаимодействовать с автоматическими транзакциями, настроенными Spring в транзакционных тестах .

2. Предварительные условия

Давайте предположим, что у нас есть некоторые интеграционные тесты в нашем весеннем приложении.

В частности, мы рассматриваем тесты, которые взаимодействуют с базой данных, например, проверяют, правильно ли ведет себя наш уровень персистентности.

Давайте рассмотрим стандартный тестовый класс, аннотированный как транзакционный:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = { HibernateConf.class })
@Transactional
public class HibernateBootstrapIntegrationTest { ... }

В таком тесте каждый метод тестирования оборачивается транзакцией, которая откатывается при выходе из метода .

Конечно, можно также аннотировать только определенные методы. Все, что мы обсудим в этой статье, относится и к этому сценарию.

3. Класс Тестовой Транзакции

Мы проведем оставшуюся часть статьи, обсуждая один класс: org.springframework.test.context.transaction.TestTransaction .

Это служебный класс с несколькими статическими методами, которые мы можем использовать для взаимодействия с транзакциями в наших тестах.

Каждый метод взаимодействует с единственной текущей транзакцией, которая выполняется во время выполнения тестового метода.

3.1. Проверка состояния Текущей транзакции

Одна вещь, которую мы часто делаем в тестах, – это проверка того, что вещи находятся в том состоянии, в котором они должны быть.

Поэтому мы можем захотеть проверить, существует ли в настоящее время активная транзакция:

assertTrue(TestTransaction.isActive());

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

assertTrue(TestTransaction.isFlaggedForRollback());

Если это так, то Spring откатит его непосредственно перед тем, как он закончится, автоматически или программно. В противном случае я совершу его непосредственно перед закрытием.

3.2. Пометка Транзакции для фиксации или отката

Мы можем программно изменить политику фиксации или отката транзакции перед ее закрытием:

TestTransaction.flagForCommit();
TestTransaction.flagForRollback();

Обычно транзакции в тестах помечаются для отката при их запуске. Однако, если метод имеет аннотацию @Commit , вместо этого они начинают помечаться для фиксации:

@Test
@Commit
public void testFlagForCommit() {
    assertFalse(TestTransaction.isFlaggedForRollback());
}

Обратите внимание, что эти методы просто помечают транзакцию, как следует из их названий. То есть транзакция не фиксируется и не откатывается немедленно, а только непосредственно перед ее завершением.

3.3. Начало и завершение транзакции

Чтобы зафиксировать или откатить транзакцию, мы либо позволяем методу выйти, либо явно завершаем его:

TestTransaction.end();

Если позже мы захотим снова взаимодействовать с базой данных, нам придется начать новую транзакцию:

TestTransaction.start();

Обратите внимание, что новая транзакция будет помечена для отката (или фиксации) в соответствии с методом по умолчанию. Другими словами, предыдущие вызовы flag For… не оказывают никакого влияния на новые транзакции.

4. Некоторые Детали Реализации

Тестовая транзакция не является чем-то волшебным. Теперь мы рассмотрим его реализацию, чтобы узнать немного больше о транзакциях в тестах с Spring.

Мы видим, что его несколько методов просто получают доступ к текущей транзакции и инкапсулируют некоторые из ее функций.

4.1. Откуда TestTransaction Получает текущую транзакцию?

Давайте сразу перейдем к коду:

TransactionContext transactionContext
  = TransactionContextHolder.getCurrentTransactionContext();

Держатель TransactionContext – это просто статическая оболочка вокруг ThreadLocal удержание Контекста транзакции .

4.2. Кто устанавливает Локальный контекст потока?

Если мы посмотрим, кто вызывает метод set CurrentTransactionContext , мы обнаружим, что есть только один вызывающий: TransactionalTestExecutionListener.beforeTestMethod .

TransactionalTestExecutionListener – это прослушиватель, который автоматически настраивается на тесты с аннотациями @Transactional .

Обратите внимание, что Контекст транзакции не содержит ссылки на многие фактические транзакции; вместо этого это просто фасад над PlatformTransactionManager .

Да, этот код сильно многоуровневый и абстрактный. Таковы, часто, основные части пружинного каркаса.

Интересно посмотреть, как, несмотря на сложность, Весна не делает никакой черной магии – просто много необходимой бухгалтерии, сантехники, обработки исключений и так далее.

5. Выводы

В этом кратком руководстве мы рассмотрели, как программно взаимодействовать с транзакциями в тестах на основе Spring.

Реализацию всех этих примеров можно найти в проекте GitHub – это проект Maven, поэтому его должно быть легко импортировать и запускать как есть.