Skip to content

Conversation

@odrotbohm
Copy link
Member

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); } }
@odrotbohm odrotbohm requested a review from sbrannen August 19, 2020 20:26
@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged or decided on label Aug 19, 2020
@sbrannen sbrannen added in: test Issues in the test module type: enhancement A general enhancement labels Aug 20, 2020
@sbrannen sbrannen self-assigned this Aug 20, 2020
@sbrannen
Copy link
Member

Thanks for the PR!

Tentatively slated for 5.3 RC1 for review and potential inclusion in 5.3

@sbrannen sbrannen added this to the 5.3 RC1 milestone Aug 20, 2020
@jhoeller jhoeller modified the milestones: 5.3 RC1, 5.3 RC2 Aug 25, 2020
…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); } }
@odrotbohm odrotbohm force-pushed the feature/published-events branch from 5170eca to 3eab764 Compare August 31, 2020 06:16
@jhoeller jhoeller removed the status: waiting-for-triage An issue we've not yet triaged or decided on label Sep 28, 2020
@sbrannen sbrannen modified the milestones: 5.3 RC2, 5.3 GA Oct 13, 2020
@sbrannen sbrannen modified the milestones: 5.3 GA, 5.3.1 Oct 26, 2020
@sbrannen sbrannen modified the milestones: 5.3.1, 5.3.2 Nov 9, 2020
@sbrannen
Copy link
Member

sbrannen commented Nov 9, 2020

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 5.3.2.

@sbrannen sbrannen modified the milestones: 5.3.2, 5.3.3 Dec 7, 2020
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
@sbrannen sbrannen changed the title Add PublishedEvents abstraction to capture ApplicationEvents published during a test method. Introduce ApplicationEvents abstraction to capture application events published during a test Dec 20, 2020
@sbrannen sbrannen closed this in 1565f4b Dec 20, 2020
@odrotbohm
Copy link
Member Author

Lovely! Thanks for all the extra effort you put into this, @sbrannen! 🙇

@sbrannen
Copy link
Member

You're very welcome!

Thanks for the idea, the prototype, and for your patience. :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

in: test Issues in the test module type: enhancement A general enhancement

4 participants