Spring надає наступні реалізації TestExecutionListener, які реєструються за умовчанням, точно так:

  • ServletTestExecutionListener: Конфігурує об'єкти-імітації API-інтерфейсу сервлетів для WebApplicationContext.

  • DirtiesContextBeforeModesTestExecutionListener: Обробляє інструкцію@DirtiesContext для режимів "перед".

  • ApplicationEventsTestExecutionListener: Забезпечує підтримку ApplicationEvents.

  • DependencyInjectionTestExecutionListener: Забезпечує впровадження залежностей для тестового екземпляра.

  • DirtiesContextTestExecutionListener: Обробляє інструкцію@DirtiesContext для режимів "після".

  • TransactionalTestExecutionListener: Забезпечує транзакційне виконання тестів із семантикою відкату за замовчуванням.

  • SqlScriptsTestExecutionListener: Виконує SQL-скрипти, налаштовані за допомогою анотації@Sql.

  • EventPublishingTestExecutionListener: Публікує події виконання тесту
    у ApplicationContext.

Реєстрація реалізацій TestExecutionListener

Ви можете зареєструвати реалізацію TestExecutionListener для тестового класу та його підкласів за допомогою анотації @TestExecutionListeners. Подробиці та приклади дивіться у підрозділі, присвяченому підтримці анотацій, та javadoc по анотації @TestExecutionListeners.

Автоматичне виявлення реалізацій TestExecutionListener за промовчанням

Реєстрація реалізацій TestExecutionListener за допомогою анотації @TestExecutionListeners підходить для спеціальних слухачів, які використовуються в обмежених сценаріях тестування. Однак реєстрація може стати скрутною, якщо спеціальний слухач необхідно використовувати у всьому тестовому комплекті. Ця проблема вирішується завдяки підтримці автоматичного виявлення реалізацій TestExecutionListener за замовчуванням через механізм SpringFactoriesLoader.

Зокрема модуль spring-test оголошує всі реалізації TestExecutionListener за замовчуванням у ключі org.springframework.test.context.TestExecutionListener у файлі властивостей META-INF/spring.factories. Сторонні фреймворки та розробники можуть вносити свої власні реалізації TestExecutionListener до списку слухачів за замовчуванням так само через власний файл властивостей META-INF/spring.factories.

Упорядкування реалізацій TestExecutionListener

Якщо фреймворк TestContext виявляє реалізації TestExecutionListener за замовчуванням через вищезгаданий механізм SpringFactoriesLoader, створені екземпляри слухачів сортуються за допомогою AnnotationAwareOrderComparator Ordered із Spring та анотацію @Order для впорядкування. AbstractTestExecutionListener та всі реалізації TestExecutionListener за промовчанням, що надаються Spring, реалізують Ordered з відповідними значеннями. Тому стороннім фреймворкам та розробникам слід переконатися, що їх реалізації TestExecutionListener за замовчуванням реєструються в правильному порядку, реалізуючи Ordered або оголошуючи інструкцію @Order. Дивіться javadoc за методами getOrder() основних реалізацій TestExecutionListener за умовчанням для отримання більш детальної інформації про те, які значення надаються кожному основному слухачеві.

Об'єднання реалізацій TestExecutionListener

Якщо спеціальний слухач TestExecutionListener зареєстрований через інструкцію @TestExecutionListeners, слухачі за замовчуванням не реєструються. У найпоширеніших сценаріях тестування це фактично змушує розробника вручну оголошувати всі слухачі за умовчанням на додаток до будь-яких спеціальних слухачів. Наступний лістинг демонструє цей стиль конфігурації:

Java
@ContextConfiguration
@TestExecutionListeners({
    MyCustomTestExecutionListener.class,
    ServletTestExecutionListener.class,
    DirtiesContextBeforeModesTestExecutionListener.class,
    DependencyInjectionTestExecutionListener.class,
    DirtiesContextTestExecutionListener.class,
    TransactionalTestExecutionListener.class,
    SqlScriptsTestExecutionListener.class
})
class MyTest {
    // Тіло класу...
}
Kotlin
@ContextConfiguration
@TestExecutionListeners(
    MyCustomTestExecutionListener::class,
    ServletTestExecutionListener::class,
    DirtiesContextBeforeModesTestExecutionListener::class,
    DependencyInjectionTestExecutionListener::class,
    DirtiesContextTestExecutionListener::class,
    TransactionalTestExecutionListener::class,
    SqlScriptsTestExecutionListener::class
)
class MyTest {
    // Тіло класу...
}

Складність цього підходу полягає в тому, що він вимагає від розробника точного знання того, які слухачі зареєстровані за умовчанням. Більше того, набір за замовчуванням слухачів може змінюватися від версії до версії – наприклад, слухач SqlScriptsTestExecutionListener був представлений у Spring Framework 4.1, а DirtiesContextBeforeModesTestExecutionListener був представлений у Spring . Більше того, сторонні фреймворки, такі як Spring Boot і Spring Security, реєструють власні реалізації TestExecutionListener за замовчуванням, використовуючи вищезгаданий механізм автоматичного виявлення.

Щоб уникнути необхідності знати та повторно оголошувати всі слухачі за умовчанням, можна встановити атрибут mergeMode анотації @TestExecutionListeners у MergeMode.MERGE_WITH_DEFAULTS. MERGE_WITH_DEFAULTS вказує, що локально оголошені слухачі мають бути об'єднані зі слухачами за промовчанням. Алгоритм об'єднання забезпечує видалення дублікатів зі списку та сортування отриманого набору об'єднаних слухачів відповідно до семантики AnnotationAwareOrderComparator, як описано в розділі "Упорядкування реалізацій TestExecutionListener". Якщо слухач реалізує Ordered або позначений інструкцією @Order, він може впливати на позицію, в якій він об'єднується зі слухачами за промовчанням. Інакше локально оголошені слухачі додаються до списку слухачів за умовчанням під час об'єднання.

Наприклад, якщо клас MyCustomTestExecutionListener у попередньому прикладі конфігурує своє значення order (наприклад, 500) так, що воно буде менше значення черговості ServletTestExecutionListener (який дорівнює 1000), то MyCustomTestExecutionListener може бути автоматично об'єднаний зі списком значень за умовчанням перед ServletTestExecutionListener приклад можна буде замінити наступним:

Java
@ContextConfiguration
@TestExecutionListeners(
    listeners = MyCustomTestExecutionListener.class,
    mergeMode = MERGE_WITH_DEFAULTS
)
class MyTest {
    // Тіло класу...
}
Kotlin
@ContextConfiguration
@TestExecutionListeners(
        listeners = [MyCustomTestExecutionListener::class],
        mergeMode = MERGE_WITH_DEFAULTS
)
class MyTest {
    // Тіло класу...
}