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 {
    // Тіло класу...
}