Introduce ApplicationEvents abstraction to capture application events published during a test#25616
Closed
odrotbohm wants to merge 1 commit intospring-projects:masterfrom
Closed
Introduce ApplicationEvents abstraction to capture application events published during a test#25616odrotbohm wants to merge 1 commit intospring-projects:masterfrom
odrotbohm wants to merge 1 commit intospring-projects:masterfrom
Conversation
Member
|
Thanks for the PR! Tentatively slated for 5.3 RC1 for review and potential inclusion in 5.3 |
…d during a test method. PublishedEventsExtension registers a composite ApplicationListener backed by thread-bound individual listeners to capture all application events published during the execution of a test method. Those would declare a PublishedEvents parameter to the method which provides API to define assertions based on the events published: @ExtendWith(PublishedEventsExtension.class) class SampleTests { @test void someTestMethod(PublishedEvents events) { // Filter events by type and predicate assertThat(events.ofType(MyEventType.class).matching(it -> …)).hasSize(2); } }
5170eca to
3eab764
Compare
Member
|
The current proposal introduces support for the following abstraction. /**
* {@code ApplicationEvents} encapsulates all {@linkplain ApplicationEvent
* application events} that were fired during the execution of a single test
* method.
*
* @author Sam Brannen
* @author Oliver Drotbohm
* @since 5.3.1
* @see ApplicationEventsExtension
* @see org.springframework.context.ApplicationEvent
* @see org.springframework.context.ApplicationListener
*/
public interface ApplicationEvents {
/**
* Stream all application events that were fired during test execution.
* @return a stream of all application events
*/
Stream<ApplicationEvent> stream();
/**
* Stream all application events or event payloads of the given type that
* were fired during test execution.
* @param <T> the event type
* @param type the type of events or payloads to stream; never {@code null}
* @return a stream of all application events or event payloads of the
* specified type
*/
<T> Stream<T> stream(Class<T> type);
}Current work on this issue can be viewed in the following branch that builds on top of this PR: master...sbrannen:issues/gh-25616-application-events-extension Tentatively slated for inclusion in |
sbrannen
added a commit
to sbrannen/spring-framework
that referenced
this pull request
Dec 15, 2020
This reworks the ApplicationEvents support so that it is based solely on a custom TestExecutionListener instead of a ContextCustomizer and a TestExecutionListener. See spring-projectsgh-25616
sbrannen
added a commit
to sbrannen/spring-framework
that referenced
this pull request
Dec 15, 2020
This reworks the ApplicationEvents support so that the current ApplicationEvents instance can be @Autowired into the test class for use with testing frameworks other than JUnit Jupiter such as JUnit 4 and TestNG. See spring-projectsgh-25616
sbrannen
added a commit
to sbrannen/spring-framework
that referenced
this pull request
Dec 15, 2020
Now that the current ApplicationEvents instance can be @Autowired into the test class, we no longer have a concrete need for a dedicated JUnit Jupiter ParameterResolver implementation since the SpringExtension for JUnit Jupiter already supports autowiring of beans from the test's ApplicationContext into test constructors, lifecycle methods, and test methods. See spring-projectsgh-25616
sbrannen
added a commit
to sbrannen/spring-framework
that referenced
this pull request
Dec 15, 2020
…piter This commit modifies the SpringExtension so that parameters of type ApplicationEvents are considered autowired candidates without the presence of @Autowired on the formal parameter declaration. This is analogous to the existing support for injecting the ApplicationContext without the parameter being annotated with @Autowired. See spring-projectsgh-25616
sbrannen
added a commit
to sbrannen/spring-framework
that referenced
this pull request
Dec 15, 2020
sbrannen
added a commit
to sbrannen/spring-framework
that referenced
this pull request
Dec 15, 2020
sbrannen
added a commit
to sbrannen/spring-framework
that referenced
this pull request
Dec 15, 2020
sbrannen
added a commit
to sbrannen/spring-framework
that referenced
this pull request
Dec 15, 2020
sbrannen
added a commit
to sbrannen/spring-framework
that referenced
this pull request
Dec 15, 2020
This commit adds proper support for ApplicationEvents when the test instance is shared -- for example, in TestNG or in JUnit Jupiter with @testinstance(PER_CLASS) semantics. See spring-projectsgh-25616
sbrannen
added a commit
to sbrannen/spring-framework
that referenced
this pull request
Dec 15, 2020
sbrannen
added a commit
to sbrannen/spring-framework
that referenced
this pull request
Dec 15, 2020
sbrannen
added a commit
to sbrannen/spring-framework
that referenced
this pull request
Dec 15, 2020
sbrannen
added a commit
to sbrannen/spring-framework
that referenced
this pull request
Dec 15, 2020
sbrannen
added a commit
to sbrannen/spring-framework
that referenced
this pull request
Dec 15, 2020
As a proof of concept, this commit introduces scoped proxy support for an ApplicationEvents bean that is managed by the SimpleThreadScope. Although this approach works in general (in terms of providing an ApplicationEvents bean that can be autowired into test classes and retrieved as a bean by third-party extensions), it has a major drawback. Specifically, an ApplicationEvents instance will be created on-demand for the current thread whenever the ThreadBoundApplicationListener attempts to access the ApplicationEvents, and this will occur even if the user has not annotated the test class with @RecordApplicationEvents. In light of the above, this commit will likely be subsequently reverted but remains in tact in the commit history for possible future consideration. See spring-projectsgh-25616
sbrannen
added a commit
to sbrannen/spring-framework
that referenced
this pull request
Dec 15, 2020
sbrannen
added a commit
to sbrannen/spring-framework
that referenced
this pull request
Dec 15, 2020
sbrannen
added a commit
to sbrannen/spring-framework
that referenced
this pull request
Dec 15, 2020
sbrannen
added a commit
to sbrannen/spring-framework
that referenced
this pull request
Dec 15, 2020
sbrannen
added a commit
to sbrannen/spring-framework
that referenced
this pull request
Dec 18, 2020
sbrannen
added a commit
to sbrannen/spring-framework
that referenced
this pull request
Dec 18, 2020
We currently do not support parameter resolution for ApplicationEvents in a test class constructor. In light of that it is better to throw an exception with an explicit error message rather than leave the user confused by a misleading exception being thrown. See spring-projectsgh-25616
sbrannen
added a commit
to sbrannen/spring-framework
that referenced
this pull request
Dec 18, 2020
Prior to this commit, if multiple tests were being executed in parallel for a test class with per-test-method test instance lifecycle semantics (e.g., in JUnit 4 and the default in JUnit Jupiter), then a race condition could occur when registering the ApplicationEventsApplicationListener in the ApplicationContext. Consequently, multiple instances of ApplicationEventsApplicationListener would be registered resulting in duplicate tracked events in ApplicationEvents. This commit avoids this race condition via a synchronized block in ApplicationEventsTestExecutionListener's registerListenerAndResolvableDependencyIfNecessary() method. See spring-projectsgh-25616
sbrannen
added a commit
to sbrannen/spring-framework
that referenced
this pull request
Dec 18, 2020
This commit also ensures that ApplicationEventsTestExecutionListener is registered in AbstractTransactionalJUnit4SpringContextTests and AbstractTransactionalTestNGSpringContextTests. See spring-projectsgh-25616
sbrannen
added a commit
to sbrannen/spring-framework
that referenced
this pull request
Dec 20, 2020
Member
Author
|
Lovely! Thanks for all the extra effort you put into this, @sbrannen! 🙇 |
Member
|
You're very welcome! Thanks for the idea, the prototype, and for your patience. :) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
PublishedEventsExtensionregisters a compositeApplicationListenerbacked by thread-bound individual listeners to capture all application events published during the execution of a test method. Those would declare aPublishedEventsparameter to the method which provides API to define assertions based on the events published: