diff --git a/spring-test/src/test/java/org/springframework/test/context/event/EventPublishingTestExecutionListenerIntegrationTests.java b/spring-test/src/test/java/org/springframework/test/context/event/EventPublishingTestExecutionListenerIntegrationTests.java index 72daa6ae7d8..b5a8fe6fbcd 100644 --- a/spring-test/src/test/java/org/springframework/test/context/event/EventPublishingTestExecutionListenerIntegrationTests.java +++ b/spring-test/src/test/java/org/springframework/test/context/event/EventPublishingTestExecutionListenerIntegrationTests.java @@ -182,7 +182,7 @@ public class EventPublishingTestExecutionListenerIntegrationTests { } @RunWith(SpringRunner.class) - @ContextConfiguration(classes = EventCaptureConfiguration.class) + @ContextConfiguration(classes = TestEventListenerConfiguration.class) @TestExecutionListeners(listeners = EventPublishingTestExecutionListener.class, mergeMode = MERGE_WITH_DEFAULTS) public static class ExampleTestCase { @@ -211,7 +211,7 @@ public class EventPublishingTestExecutionListenerIntegrationTests { @Configuration @EnableAsync(proxyTargetClass = true) - static class EventCaptureConfiguration extends AsyncConfigurerSupport { + static class TestEventListenerConfiguration extends AsyncConfigurerSupport { @Override public Executor getAsyncExecutor() { @@ -231,88 +231,97 @@ public class EventPublishingTestExecutionListenerIntegrationTests { return mock(TestExecutionListener.class); } + /** + * The {@code @Async} test event listener method must reside in a separate + * component since {@code @Async} is not supported on methods in + * {@code @Configuration} classes. + */ @Bean - EventCaptureBean eventCaptureBean() { - return new EventCaptureBean(listener()); - } - - } - - static class TrackingAsyncUncaughtExceptionHandler implements AsyncUncaughtExceptionHandler { - - static volatile Throwable asyncException; - - - @Override - public void handleUncaughtException(Throwable exception, Method method, Object... params) { - asyncException = exception; - countDownLatch.countDown(); - } - } - - // MUST be annotated with @Component due to a change in Spring 5.1 that - // does not consider beans in a package starting with "org.springframework" - // to be event listeners unless they are also components. See - // org.springframework.context.event.EventListenerMethodProcessor.isSpringContainerClass(Class) - // for details. - @Component - static class EventCaptureBean { - - final TestExecutionListener listener; - - - EventCaptureBean(TestExecutionListener listener) { - this.listener = listener; + AsyncTestEventComponent asyncTestEventComponent() { + return new AsyncTestEventComponent(listener()); } @BeforeTestClass("#root.event.source.testClass.name matches '.+TestCase'") public void beforeTestClass(BeforeTestClassEvent e) throws Exception { - this.listener.beforeTestClass(e.getSource()); + listener().beforeTestClass(e.getSource()); } @PrepareTestInstance("#a0.testContext.testClass.name matches '.+TestCase'") public void prepareTestInstance(PrepareTestInstanceEvent e) throws Exception { - this.listener.prepareTestInstance(e.getSource()); + listener().prepareTestInstance(e.getSource()); } @BeforeTestMethod("#p0.testContext.testMethod.isAnnotationPresent(T(org.springframework.test.context.event.EventPublishingTestExecutionListenerIntegrationTests.Traceable))") public void beforeTestMethod(BeforeTestMethodEvent e) throws Exception { - this.listener.beforeTestMethod(e.getSource()); + listener().beforeTestMethod(e.getSource()); } @BeforeTestMethod("event.testContext.testMethod.name == 'testWithFailingEventListener'") public void beforeTestMethodWithFailure(BeforeTestMethodEvent event) throws Exception { - this.listener.beforeTestMethod(event.getSource()); + listener().beforeTestMethod(event.getSource()); throw new RuntimeException("Boom!"); } - @BeforeTestMethod("event.testContext.testMethod.name == 'testWithFailingAsyncEventListener'") - @Async - public void beforeTestMethodWithAsyncFailure(BeforeTestMethodEvent event) throws Exception { - this.listener.beforeTestMethod(event.getSource()); - throw new RuntimeException(String.format("Asynchronous exception for test method [%s] in thread [%s]", - event.getTestContext().getTestMethod().getName(), Thread.currentThread().getName())); - } - @BeforeTestExecution public void beforeTestExecution(BeforeTestExecutionEvent e) throws Exception { - this.listener.beforeTestExecution(e.getSource()); + listener().beforeTestExecution(e.getSource()); } @AfterTestExecution public void afterTestExecution(AfterTestExecutionEvent e) throws Exception { - this.listener.afterTestExecution(e.getSource()); + listener().afterTestExecution(e.getSource()); } @AfterTestMethod("event.testContext.testMethod.isAnnotationPresent(T(org.springframework.test.context.event.EventPublishingTestExecutionListenerIntegrationTests.Traceable))") public void afterTestMethod(AfterTestMethodEvent e) throws Exception { - this.listener.afterTestMethod(e.getSource()); + listener().afterTestMethod(e.getSource()); } @AfterTestClass("#afterTestClassEvent.testContext.testClass.name matches '.+TestCase'") public void afterTestClass(AfterTestClassEvent afterTestClassEvent) throws Exception { - this.listener.afterTestClass(afterTestClassEvent.getSource()); + listener().afterTestClass(afterTestClassEvent.getSource()); } + + } + + /** + * MUST be annotated with {@code @Component} due to a change in Spring 5.1 that + * does not consider beans in a package starting with "org.springframework" to be + * event listeners unless they are also components. + * + * @see org.springframework.context.event.EventListenerMethodProcessor#isSpringContainerClass + */ + @Component + static class AsyncTestEventComponent { + + final TestExecutionListener listener; + + + AsyncTestEventComponent(TestExecutionListener listener) { + this.listener = listener; + } + + @BeforeTestMethod("event.testContext.testMethod.name == 'testWithFailingAsyncEventListener'") + @Async + public void beforeTestMethodWithAsyncFailure(BeforeTestMethodEvent event) throws Exception { + this.listener.beforeTestMethod(event.getSource()); + throw new RuntimeException(String.format("Asynchronous exception for test method [%s] in thread [%s]", + event.getTestContext().getTestMethod().getName(), Thread.currentThread().getName())); + } + + } + + static class TrackingAsyncUncaughtExceptionHandler implements AsyncUncaughtExceptionHandler { + + static volatile Throwable asyncException; + + + @Override + public void handleUncaughtException(Throwable exception, Method method, Object... params) { + asyncException = exception; + countDownLatch.countDown(); + } + } }