Починаючи з версії Spring Framework 5.3.3, фреймворк TestContext забезпечує підтримку запису подій програми, опублікованих у ApplicationContext, щоб можна було щодо цих подій виконувати твердження в тестах. Всі події, опубліковані під час виконання одного тесту, доступні через API-інтерфейс ApplicationEvents, який дозволяє обробляти події як java.util.Stream.

Щоб використовувати ApplicationEvents у своїх тестах, зроби таке.

  • Переконайся, що твій тестовий клас анотований або мета-анотований за допомогою @RecordApplicationEvents.

  • Переконайся, що ApplicationEventsTestExecutionListener зареєстровано. Зверни увагу, що ApplicationEventsTestExecutionListener зареєстровано за замовчуванням, а реєструвати його вручну потрібно лише в тому випадку, якщо у тебе є спеціальна конфігурація через анотацію @TestExecutionListeners, яка не включає слухачів за замовчуванням.

  • Анотуй поле типу ApplicationEvents за допомогою анотації @Autowired та використовуй цей екземпляр ApplicationEvents у твоїх тестових методах та методах життєвого циклу (наприклад, методи, позначені анотаціями @BeforeEach та @AfterEach, в JUnit Jupiter).

    • При використанні розширення SpringExtension для JUnit Jupiter можна оголосити параметр методу типу ApplicationEvents у тестовому методі або методі життєвого циклу як альтернативу полю, анотованому @Autowired, у тестовому класі.

Наступний тестовий клас використовує SpringExtension для JUnit Jupiter та AssertJ для затвердження типів подій програми, що публікуються під час виклику методу в компоненті, керованому Spring:

Java
@SpringJUnitConfig(/* ... */)
@RecordApplicationEvents 
class OrderServiceTests {
    @Autowired
    OrderService orderService;
    @Autowired
    ApplicationEvents events; 
    @Test
    void submitOrder() {
        // Викликаємо метод OrderService, який публікує подію
        orderService.submitOrder(new Order(/*...*/));
        // Перевіряємо, щоб подія OrderSubmitted була опублікована
        long numEvents = events.stream(OrderSubmitted.class).count(); 
        assertThat(numEvents).isEqualTo(1);
    }
}
  1. Анотуємо тестовий клас за допомогою @RecordApplicationEvents.
  2. Впроваджуємо екземпляр ApplicationEvents для поточного тесту.
  3. Використовуємо API-інтерфейс ApplicationEvents, щоб підрахувати, скільки подій OrderSubmitted було опубліковано.
Kotlin
@SpringJUnitConfig(/* ... */)
@RecordApplicationEvents 
class OrderServiceTests {
    @Autowired
    lateinit var orderService: OrderService
    @Autowired
    lateinit var events: ApplicationEvents 
    @Test
    fun submitOrder() {
        // Викликаємо метод OrderService, який публікує подію
        orderService.submitOrder(Order(/* ... */))
        // Перевіряємо, щоб подія OrderSubmitted була опублікована
        val numEvents = events.stream(OrderSubmitted::class).count() 
        assertThat(numEvents).isEqualTo(1)
    }
}
  1. Анотуємо тестовий клас за допомогою @RecordApplicationEvents.
  2. Впроваджуємо екземпляр ApplicationEvents для поточного тесту.
  3. Використовуємо API-інтерфейс ApplicationEvents, щоб підрахувати, скільки подій OrderSubmitted було опубліковано.

Див. javadoc ApplicationEvents для отримання додаткової інформації про API-інтерфейс ApplicationEvents.

Події виконання тесту

Слухач EventPublishingTestExecutionListener, представлений у Spring Framework 5.2, пропонує альтернативний підхід до реалізації спеціального TestExecutionListener. Компоненти в ApplicationContext тесту можуть прослуховувати такі події, що публікуються EventPublishingTestExecutionListener, кожна з яких відповідає методу в API-інтерфейсі TestExecutionListener.

  • BeforeTestClassEvent

  • PrepareTestInstanceEvent

  • BeforeTestMethodEvent

  • BeforeTestExecutionEvent

  • AfterTestExecutionEvent

  • AfterTestMethodEvent

  • AfterTestClassEvent

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

Слухач EventPublishingTestExecutionListener зареєстрований за замовчуванням; однак він публікує події лише в тому випадку, якщо ApplicationContext вже завантажено. Це запобігає непотрібному або надто ранньому завантаженню ApplicationContext.

Отже, подію BeforeTestClassEvent буде опубліковано лише після того, як ApplicationContext буде завантажено іншим TestExecutionListener. Наприклад, при наборі реалізацій TestExecutionListener, зареєстрованих за замовчуванням, подія BeforeTestClassEvent не буде опублікована для першого тестового класу, який використовує певний тестовий ApplicationContext, але подія BeforeTestClassEvent буде опублікована для будь-якого наступного тестового класу в тому ж тестовому комплекті, який використовує той же тестовий ApplicationContext, оскільки контекст вже буде завантажений при виконанні наступних тестових класів (якщо контекст не був видалений з ContextCache через анотацію @DirtiesContext або політику витіснення при досягненні максимального розміру).

Якщо потрібно, щоб подія BeforeTestClassEvent завжди публікувалася для кожного тестового класу, необхідно зареєструвати TestExecutionListener, який завантажує ApplicationContext у зворотному виклику beforeTestClass, і цей TestExecutionListener має бути зареєстрований перед EventPublishingTestExecutionListener.

Аналогічно, якщо анотація @DirtiesContext використовується для видалення ApplicationContext з кешу контексту після останнього тестового методу в даному тестовому класі, подія AfterTestClassEvent не буде опубліковано для цього тестового класу.

Щоб прослуховувати події виконання тесту, бін Spring може вибрати реалізацію інтерфейсу org.springframework.context.ApplicationListener. Крім того, методи слухачів можуть бути анотовані @EventListener та налаштовані на прослуховування одного з конкретних типів подій, перерахованих вище (див. Слухачі (одержувачі) подій на основі анотацій).
У зв'язку з популярністю цього підходу Spring надає наступні спеціальні анотації @EventListener для спрощення реєстрації слухачів подій виконання тесту. Ці анотації знаходяться в пакеті org.springframework.test.context.event.annotation.

  • @BeforeTestClass

  • @PrepareTestInstance

  • @BeforeTestMethod

  • @BeforeTestExecution

  • @AfterTestExecution

  • @AfterTestMethod

  • @AfterTestClass

Обробка винятків

За замовчуванням, якщо слухач подій виконання тесту генерує виняток при споживанні події, цей виняток передається у базовий тестовий фреймворк, що використовується (наприклад, JUnit або TestNG). Наприклад, якщо використання події BeforeTestMethodEvent призводить до виникнення винятку, то відповідний тестовий метод у результаті винятку завершиться помилкою. І навпаки, якщо асинхронний слухач подій виконання тесту генерує виняток, він не поширюється до базового тестового фреймворку. Для отримання більш детальної інформації про асинхронну обробку винятків звернися до javadoc за @EventListener на рівні класу.

Асинхронні слухачі

Якщо потрібно, щоб певний слухач подій виконання тесту обробляв події асинхронно, можна використовувати звичайну підтримку анотації @Async із Spring.
Для отримання більш детальної інформації звернися до javadoc за @EventListener на рівні класу.