Интеграционное тестирование в Spring: TestContext Framework, аннотации транзакций

В следующем примере на основе JUnit Jupiter показан вымышленный сценарий тестирования интеграции, в котором выделены все аннотации, связанные с транзакциями. Этот пример не предназначен для демонстрации передового опыта, а скорее для демонстрации того, как можно использовать эти аннотации.

@SpringJUnitConfig 
@Transactional(transactionManager = "txMgr") 
@Commit 
class FictitiousTransactionalTest {

    @BeforeTransaction
    void verifyInitialDatabaseState() {
        // логика для проверки 
        // начального состояния перед запуском транзакции
    }

    @BeforeEach
    void setUpTestDataWithinTransaction() {
        // настраиваем тестовые данные внутри транзакции
    }

    @Test
    // переопределяет аннотацию @Commit уровня класса
    @Rollback
    void modifyDatabaseWithinTransaction() {
        // логика, которая использует 
        // тестовые данные и изменяет состояние базы данных
    }

    @AfterEach
    void tearDownWithinTransaction() {
        // запускаем логику "разрыва" внутри транзакции
    }

    @AfterTransaction
    void verifyFinalDatabaseState() {
        // логика для проверки 
        // конечного состояния после отката транзакции
    }

}

Избегайте ложных срабатываний при тестировании кода ORM

Когда вы тестируете код приложения, который манипулирует состоянием сеанса Hibernate или контекстом сохранения JPA, не забудьте очистить базовую единицу работы в тестовых методах, которые запускают этот код. Неспособность очистить базовую единицу работы может привести к ложным срабатываниям: ваш тест проходит успешно, но тот же код вызывает исключение в действующей производственной среде. Обратите внимание, что это применимо к любому ORM фреймворку, который поддерживает единицу работы в памяти. В следующем примере тестового случая на основе Hibernate один метод демонстрирует ложное срабатывание, а другой метод правильно отображает результаты сброса сеанса:

@Autowired
SessionFactory sessionFactory;

@Transactional
@Test // исключение не ожидается!
public void falsePositive() {
    updateEntityInHibernateSession();
    // Ложное срабатывание: исключение будет 
    // сгенерировано после перехода в спящий режим.
    // Сессия окончательно очищена 
    // (т.е. в производственном коде)
}

@Transactional
@Test(expected = ...)
public void updateWithSessionFlush() {
    updateEntityInHibernateSession();
    // Ручной flush необходим, 
    // чтобы избежать ложного срабатывания теста
    sessionFactory.getCurrentSession().flush();
}

// ...

В следующем примере показаны методы сопоставления для JPA:

// ...

@PersistenceContext
EntityManager entityManager;

@Transactional
@Test // исключение не ожидается!
public void falsePositive() {
    updateEntityInJpaPersistenceContext();
    // Ложное срабатывание: будет сгенерировано исключение, 
    // когда JPA EntityManager окончательно очищен 
    // (т.е. в производственном коде)
}

@Transactional
@Test(expected = ...)
public void updateWithEntityManagerFlush() {
    updateEntityInJpaPersistenceContext();
    // Ручной flush необходим, 
    // чтобы избежать ложного срабатывания теста
    entityManager.flush();
}

// ...


Читайте также:


Комментарии

Популярные сообщения из этого блога

Методы класса Object в Java

Как получить текущий timestamp в Java

Основные опции JVM для повышения производительности и отладки