Browse Source

Merge branch '6.2.x'

pull/35363/head
Sam Brannen 4 months ago
parent
commit
472f844256
  1. 51
      framework-docs/modules/ROOT/pages/testing/testcontext-framework/application-events.adoc
  2. 15
      spring-test/src/main/java/org/springframework/test/context/event/ApplicationEvents.java

51
framework-docs/modules/ROOT/pages/testing/testcontext-framework/application-events.adoc

@ -2,10 +2,10 @@
= Application Events = Application Events
The TestContext framework provides support for recording The TestContext framework provides support for recording
xref:core/beans/context-introduction.adoc#context-functionality-events[application events] published in the xref:core/beans/context-introduction.adoc#context-functionality-events[application events]
`ApplicationContext` so that assertions can be performed against those events within published in the `ApplicationContext` so that assertions can be performed against those
tests. All events published during the execution of a single test are made available via events within tests. All events published during the execution of a single test are made
the `ApplicationEvents` API which allows you to process the events as a available via the `ApplicationEvents` API which allows you to process the events as a
`java.util.Stream`. `java.util.Stream`.
To use `ApplicationEvents` in your tests, do the following. To use `ApplicationEvents` in your tests, do the following.
@ -16,16 +16,23 @@ To use `ApplicationEvents` in your tests, do the following.
that `ApplicationEventsTestExecutionListener` is registered by default and only needs that `ApplicationEventsTestExecutionListener` is registered by default and only needs
to be manually registered if you have custom configuration via to be manually registered if you have custom configuration via
`@TestExecutionListeners` that does not include the default listeners. `@TestExecutionListeners` that does not include the default listeners.
* Annotate a field of type `ApplicationEvents` with `@Autowired` and use that instance of * When using the
`ApplicationEvents` in your test and lifecycle methods (such as `@BeforeEach` and xref:testing/testcontext-framework/support-classes.adoc#testcontext-junit-jupiter-extension[SpringExtension for JUnit Jupiter],
`@AfterEach` methods in JUnit Jupiter). declare a method parameter of type `ApplicationEvents` in a `@Test`, `@BeforeEach`, or
** When using the xref:testing/testcontext-framework/support-classes.adoc#testcontext-junit-jupiter-extension[SpringExtension for JUnit Jupiter], you may declare a method `@AfterEach` method.
parameter of type `ApplicationEvents` in a test or lifecycle method as an alternative ** Since `ApplicationEvents` is scoped to the lifecycle of the current test method, this
to an `@Autowired` field in the test class. is the recommended approach.
* Alternatively, you can annotate a field of type `ApplicationEvents` with `@Autowired`
and use that instance of `ApplicationEvents` in your test and lifecycle methods.
NOTE: `ApplicationEvents` is registered with the `ApplicationContext` as a _resolvable
dependency_ which is scoped to the lifecycle of the current test method. Consequently,
`ApplicationEvents` cannot be accessed outside the lifecycle of a test method and cannot be
`@Autowired` into the constructor of a test class.
The following test class uses the `SpringExtension` for JUnit Jupiter and The following test class uses the `SpringExtension` for JUnit Jupiter and
{assertj-docs}[AssertJ] to assert the types of application events {assertj-docs}[AssertJ] to assert the types of application events published while
published while invoking a method in a Spring-managed component: invoking a method in a Spring-managed component:
// Don't use "quotes" in the "subs" section because of the asterisks in /* ... */ // Don't use "quotes" in the "subs" section because of the asterisks in /* ... */
[tabs] [tabs]
@ -38,16 +45,10 @@ Java::
@RecordApplicationEvents // <1> @RecordApplicationEvents // <1>
class OrderServiceTests { class OrderServiceTests {
@Autowired
OrderService orderService;
@Autowired
ApplicationEvents events; // <2>
@Test @Test
void submitOrder() { void submitOrder(@Autowired OrderService service, ApplicationEvents events) { // <2>
// Invoke method in OrderService that publishes an event // Invoke method in OrderService that publishes an event
orderService.submitOrder(new Order(/* ... */)); service.submitOrder(new Order(/* ... */));
// Verify that an OrderSubmitted event was published // Verify that an OrderSubmitted event was published
long numEvents = events.stream(OrderSubmitted.class).count(); // <3> long numEvents = events.stream(OrderSubmitted.class).count(); // <3>
assertThat(numEvents).isEqualTo(1); assertThat(numEvents).isEqualTo(1);
@ -66,16 +67,10 @@ Kotlin::
@RecordApplicationEvents // <1> @RecordApplicationEvents // <1>
class OrderServiceTests { class OrderServiceTests {
@Autowired
lateinit var orderService: OrderService
@Autowired
lateinit var events: ApplicationEvents // <2>
@Test @Test
fun submitOrder() { fun submitOrder(@Autowired service: OrderService, events: ApplicationEvents) { // <2>
// Invoke method in OrderService that publishes an event // Invoke method in OrderService that publishes an event
orderService.submitOrder(Order(/* ... */)) service.submitOrder(Order(/* ... */))
// Verify that an OrderSubmitted event was published // Verify that an OrderSubmitted event was published
val numEvents = events.stream(OrderSubmitted::class).count() // <3> val numEvents = events.stream(OrderSubmitted::class).count() // <3>
assertThat(numEvents).isEqualTo(1) assertThat(numEvents).isEqualTo(1)

15
spring-test/src/main/java/org/springframework/test/context/event/ApplicationEvents.java

@ -33,14 +33,21 @@ import org.springframework.context.ApplicationEvent;
* to be manually registered if you have custom configuration via * to be manually registered if you have custom configuration via
* {@link org.springframework.test.context.TestExecutionListeners @TestExecutionListeners} * {@link org.springframework.test.context.TestExecutionListeners @TestExecutionListeners}
* that does not include the default listeners.</li> * that does not include the default listeners.</li>
* <li>Annotate a field of type {@code ApplicationEvents} with * <li>With JUnit Jupiter, declare a parameter of type {@code ApplicationEvents}
* in a {@code @Test}, {@code @BeforeEach}, or {@code @AfterEach} method. Since
* {@code ApplicationEvents} is scoped to the lifecycle of the current test method,
* this is the recommended approach.</li>
* <li>Alternatively, you can annotate a field of type {@code ApplicationEvents} with
* {@link org.springframework.beans.factory.annotation.Autowired @Autowired} and * {@link org.springframework.beans.factory.annotation.Autowired @Autowired} and
* use that instance of {@code ApplicationEvents} in your test and lifecycle methods.</li> * use that instance of {@code ApplicationEvents} in your test and lifecycle methods.</li>
* <li>With JUnit Jupiter, you may optionally declare a parameter of type
* {@code ApplicationEvents} in a test or lifecycle method as an alternative to
* an {@code @Autowired} field in the test class.</li>
* </ul> * </ul>
* *
* <p>NOTE: {@code ApplicationEvents} is registered with the {@code ApplicationContext} as a
* {@linkplain org.springframework.beans.factory.config.ConfigurableListableBeanFactory#registerResolvableDependency
* resolvable dependency} which is scoped to the lifecycle of the current test method.
* Consequently, {@code ApplicationEvents} cannot be accessed outside the lifecycle of a
* test method and cannot be {@code @Autowired} into the constructor of a test class.
*
* @author Sam Brannen * @author Sam Brannen
* @author Oliver Drotbohm * @author Oliver Drotbohm
* @since 5.3.3 * @since 5.3.3

Loading…
Cancel
Save