Одна из основных функций Spring - функция публикации событий. Мы можем использовать события для разделения частей нашего приложения и реализации шаблона публикации-подписки. Одна часть нашего приложения может публиковать событие, на которое реагируют несколько слушателей (даже асинхронно). В рамках Spring Framework 5.3.3 (Spring Boot 2.4.2) теперь мы можем записывать и проверять все опубликованные события ( ApplicationEvent) при тестировании приложений Spring Boot с использованием @RecrodApplicationEvents. Чтобы использовать эту функцию, нам нужен только Spring Boot Starter Test, который является частью каждого проекта Spring Boot, который вы загружаете на start.spring.io . Обязательно используйте версию Spring Boot >= 2.4.2, так как нам нужна версия Spring Framework >= 5.3.3. Для наших тестов есть одно дополнительное требование: нам нужно работать со SpringTestContext поскольку публикация событий является основной функциональностью платформы ApplicationContext. Следовательно, она не работает для модульного теста, где не используется поддержка инфраструктуры Spring TestContext. Есть несколько аннотаций тестовых срезов Spring Boot, которые удобно загружают контекст для нашего теста. В качестве примера мы протестируем класс Java, который выдает UserCreationEvent, когда мы успешно создаем нового пользователя. Событие включает метаданные о пользователе, актуальные для последующих задач: Начиная со Spring Framework 4.2, нам не нужно расширять абстрактный класс ApplicationEvent и мы можем использовать любой POJO в качестве нашего класса событий. В следующий статье привелено отличное введение в события приложений с помощью Spring Boot. Наш UserService создает и хранит наших новых пользователей. Мы можем создать как одного пользователя, так и группу пользователей: Как только пользователь станет частью нашей системы, мы уведомим другие компоненты нашего приложения, опубликовав файл UserCreationEvent. Например, наше приложение выполняет две дополнительные операции всякий раз, когда мы запускаем такое UserCreationEvent: Давайте напишем наш первый тест, который гарантирует, что UserService генерирует событие всякий раз, когда мы создаем нового пользователя. Мы инструктируем Spring фиксировать наши события с помощью @RecordApplicationEvents аннотации поверх нашего тестового класса: После того, как мы выполняем публичный метод нашего класса испытываемый (createUser из UserService в этом примере), мы можем запросить все захваченные события из бинов ApplicationEvents, которые мы внедряем в наш тест. Открытый .stream()метод класса ApplicationEvents позволяет просмотреть все события, записанные для теста. Есть перегруженная версия .stream(), в которой мы запрашиваем поток только определенных событий. Несмотря на то, что мы генерируем только одно событие из нашего приложения, Spring захватывает четыре события для теста выше. Остальные три события относятся к Spring, как и PrepareInstanceEvent в среде TestContext. Поскольку мы используем JUnit Jupiter и SpringExtension (зарегистрированный для нас при использовании @SpringBootTest), мы также можем внедрить bean-компонент ApplicationEvents в метод жизненного цикла JUnit или непосредственно в тест: Экземпляр ApplicationEvents создается до и удаляется после каждого теста как часть текущего потока. Следовательно, вы даже можете использовать внедрение поля и @TestInstance(TestInstance.Lifecycle.PER_CLASS)делить тестовый экземпляр между несколькими тестами ( PER_METHOD по умолчанию). Обратите внимание, что запуск всего контекста Spring @SpringBootTest для такого теста может быть излишним. Мы также могли бы написать тест, который заполняет минимальный Spring TestContext только нашим bean-компонентом UserService, чтобы убедиться, что UserCreationEvent  опубликован: … Или используйте альтернативный подход к тестированию. В зависимости от того, чего вы хотите достичь с помощью теста, может быть достаточно проверить эту функциональность с помощью модульного теста: Обратите внимание, что здесь мы не используем никакой поддержки Spring Test и полагаемся исключительно на Mockito и JUnit Jupiter. Другой подход заключается в том, чтобы не проверять события публикации явно, а проверять весь сценарий использования с помощью интеграционного теста: В этом случае нам нужно будет проверить результат работы наших слушателей событий и, например, проверить, что мы помещаем сообщение в очередь или увеличиваем счетчик. Все различные подходы сводятся к тестированию поведения и состояния. Благодаря новой функции @RecordApplicationEvents в Spring Test у нас может возникнуть соблазн провести больше поведенческих тестов и проверить внутреннюю часть нашей реализации. В общем, мы должны сосредоточиться на тестировании состояния (также известном как результат), поскольку оно поддерживает беспроблемный рефакторинг. Представьте себе следующее: мы используем, ApplicationEvent чтобы разделять части нашего приложения и гарантировать, что это событие запускается во время теста. Через две недели мы решаем убрать / переработать эту развязку (по каким-то причинам). Наш вариант использования может по-прежнему работать, как ожидалось, но наш тест теперь не проходит, потому что мы делаем предположения о технической реализации, проверяя, сколько событий мы опубликовали. Помните об этом и не перегружайте свои тесты деталями реализации (если вы хотите провести рефакторинг в будущем :). Тем не менее, есть определенные тестовые сценарии, когда функция @RecordApplicationEvents очень помогает. Исходный код со всеми альтернативными вариантами для тестирования Spring Event с помощью Spring Boot доступен на GitHub.