diff --git a/spring-test/src/main/java/org/springframework/test/context/event/EventPublishingTestExecutionListener.java b/spring-test/src/main/java/org/springframework/test/context/event/EventPublishingTestExecutionListener.java index d25af05b3d38..d6b5c9cef4f3 100644 --- a/spring-test/src/main/java/org/springframework/test/context/event/EventPublishingTestExecutionListener.java +++ b/spring-test/src/main/java/org/springframework/test/context/event/EventPublishingTestExecutionListener.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2022 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,16 +17,12 @@ package org.springframework.test.context.event; import org.springframework.test.context.TestContext; -import org.springframework.test.context.TestExecutionListener; import org.springframework.test.context.support.AbstractTestExecutionListener; /** - * {@link org.springframework.test.context.TestExecutionListener TestExecutionListener} - * that publishes test execution events to the + * {@code TestExecutionListener} that publishes test execution events to the * {@link org.springframework.context.ApplicationContext ApplicationContext} - * for the currently executing test. Events are only published if the - * {@code ApplicationContext} {@linkplain TestContext#hasApplicationContext() - * has already been loaded}. + * for the currently executing test. * *
These events may be consumed for various reasons, such as resetting mock * beans or tracing test execution. One advantage of consuming test events rather - * than implementing a custom {@link TestExecutionListener} is that test events - * may be consumed by any Spring bean registered in the test {@code ApplicationContext}, - * and such beans may benefit directly from dependency injection and other features - * of the {@code ApplicationContext}. In contrast, a {@link TestExecutionListener} - * is not a bean in the {@code ApplicationContext}. + * than implementing a custom {@link org.springframework.test.context.TestExecutionListener + * TestExecutionListener} is that test events may be consumed by any Spring bean + * registered in the test {@code ApplicationContext}, and such beans may benefit + * directly from dependency injection and other features of the {@code ApplicationContext}. + * In contrast, a {@code TestExecutionListener} is not a bean in the {@code ApplicationContext}. + * + *
Note that the {@code EventPublishingTestExecutionListener} is registered by + * default; however, it only publishes events if the {@code ApplicationContext} + * {@linkplain TestContext#hasApplicationContext() has already been loaded}. This + * prevents the {@code ApplicationContext} from being loaded unnecessarily or too + * early. Consequently, a {@code BeforeTestClassEvent} will not be published until + * after the {@code ApplicationContext} has been loaded by another + * {@code TestExecutionListener}. For example, with the default set of + * {@code TestExecutionListeners} registered, a {@code BeforeTestClassEvent} will + * not be published for the first test class that uses a particular test + * {@code ApplicationContext}, but a {@code BeforeTestClassEvent} will be published + * for any subsequent test class in the same test suite that uses the same test + * {@code ApplicationContext} since the context will already have been loaded + * when subsequent test classes run (as long as the context has not been removed + * from the {@link org.springframework.test.context.cache.ContextCache ContextCache} + * via {@link org.springframework.test.annotation.DirtiesContext @DirtiesContext} + * or the max-size eviction policy). If you wish to ensure that a + * {@code BeforeTestClassEvent} is published for every test class, you need to + * register a {@code TestExecutionListener} that loads the {@code ApplicationContext} + * in the {@link org.springframework.test.context.TestExecutionListener#beforeTestClass + * beforeTestClass} callback, and that {@code TestExecutionListener} must be registered + * before the {@code EventPublishingTestExecutionListener}. * *
By default, if a test event listener throws an exception while consuming diff --git a/spring-test/src/main/java/org/springframework/test/context/event/annotation/AfterTestClass.java b/spring-test/src/main/java/org/springframework/test/context/event/annotation/AfterTestClass.java index aab12268d0d2..b89efd59ce0a 100644 --- a/spring-test/src/main/java/org/springframework/test/context/event/annotation/AfterTestClass.java +++ b/spring-test/src/main/java/org/springframework/test/context/event/annotation/AfterTestClass.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2022 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -49,6 +49,8 @@ *
The {@code EventPublishingTestExecutionListener} must be registered in order * for this annotation to have an effect — for example, via * {@link org.springframework.test.context.TestExecutionListeners @TestExecutionListeners}. + * Note, however, that the {@code EventPublishingTestExecutionListener} is registered + * by default. * * @author Frank Scheffler * @author Sam Brannen diff --git a/spring-test/src/main/java/org/springframework/test/context/event/annotation/AfterTestExecution.java b/spring-test/src/main/java/org/springframework/test/context/event/annotation/AfterTestExecution.java index cd2d297d51cb..f91d2612418e 100644 --- a/spring-test/src/main/java/org/springframework/test/context/event/annotation/AfterTestExecution.java +++ b/spring-test/src/main/java/org/springframework/test/context/event/annotation/AfterTestExecution.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2022 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -49,6 +49,8 @@ *
The {@code EventPublishingTestExecutionListener} must be registered in order * for this annotation to have an effect — for example, via * {@link org.springframework.test.context.TestExecutionListeners @TestExecutionListeners}. + * Note, however, that the {@code EventPublishingTestExecutionListener} is registered + * by default. * * @author Frank Scheffler * @author Sam Brannen diff --git a/spring-test/src/main/java/org/springframework/test/context/event/annotation/AfterTestMethod.java b/spring-test/src/main/java/org/springframework/test/context/event/annotation/AfterTestMethod.java index 0e3b9b6b8dee..ed805c30e588 100644 --- a/spring-test/src/main/java/org/springframework/test/context/event/annotation/AfterTestMethod.java +++ b/spring-test/src/main/java/org/springframework/test/context/event/annotation/AfterTestMethod.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2022 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -49,6 +49,8 @@ *
The {@code EventPublishingTestExecutionListener} must be registered in order * for this annotation to have an effect — for example, via * {@link org.springframework.test.context.TestExecutionListeners @TestExecutionListeners}. + * Note, however, that the {@code EventPublishingTestExecutionListener} is registered + * by default. * * @author Frank Scheffler * @author Sam Brannen diff --git a/spring-test/src/main/java/org/springframework/test/context/event/annotation/BeforeTestClass.java b/spring-test/src/main/java/org/springframework/test/context/event/annotation/BeforeTestClass.java index 709544133ef0..1c2566212d7d 100644 --- a/spring-test/src/main/java/org/springframework/test/context/event/annotation/BeforeTestClass.java +++ b/spring-test/src/main/java/org/springframework/test/context/event/annotation/BeforeTestClass.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2022 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -49,6 +49,8 @@ *
The {@code EventPublishingTestExecutionListener} must be registered in order * for this annotation to have an effect — for example, via * {@link org.springframework.test.context.TestExecutionListeners @TestExecutionListeners}. + * Note, however, that the {@code EventPublishingTestExecutionListener} is registered + * by default. * * @author Frank Scheffler * @author Sam Brannen diff --git a/spring-test/src/main/java/org/springframework/test/context/event/annotation/BeforeTestExecution.java b/spring-test/src/main/java/org/springframework/test/context/event/annotation/BeforeTestExecution.java index a28c13ff76d4..3560c56d735d 100644 --- a/spring-test/src/main/java/org/springframework/test/context/event/annotation/BeforeTestExecution.java +++ b/spring-test/src/main/java/org/springframework/test/context/event/annotation/BeforeTestExecution.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2022 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -49,6 +49,8 @@ *
The {@code EventPublishingTestExecutionListener} must be registered in order * for this annotation to have an effect — for example, via * {@link org.springframework.test.context.TestExecutionListeners @TestExecutionListeners}. + * Note, however, that the {@code EventPublishingTestExecutionListener} is registered + * by default. * * @author Frank Scheffler * @author Sam Brannen diff --git a/spring-test/src/main/java/org/springframework/test/context/event/annotation/BeforeTestMethod.java b/spring-test/src/main/java/org/springframework/test/context/event/annotation/BeforeTestMethod.java index 3da957494b65..0734b9cce783 100644 --- a/spring-test/src/main/java/org/springframework/test/context/event/annotation/BeforeTestMethod.java +++ b/spring-test/src/main/java/org/springframework/test/context/event/annotation/BeforeTestMethod.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2022 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -49,6 +49,8 @@ *
The {@code EventPublishingTestExecutionListener} must be registered in order * for this annotation to have an effect — for example, via * {@link org.springframework.test.context.TestExecutionListeners @TestExecutionListeners}. + * Note, however, that the {@code EventPublishingTestExecutionListener} is registered + * by default. * * @author Frank Scheffler * @author Sam Brannen diff --git a/spring-test/src/main/java/org/springframework/test/context/event/annotation/PrepareTestInstance.java b/spring-test/src/main/java/org/springframework/test/context/event/annotation/PrepareTestInstance.java index 50ad3f994095..4086f20a6ff3 100644 --- a/spring-test/src/main/java/org/springframework/test/context/event/annotation/PrepareTestInstance.java +++ b/spring-test/src/main/java/org/springframework/test/context/event/annotation/PrepareTestInstance.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2022 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -49,6 +49,8 @@ *
The {@code EventPublishingTestExecutionListener} must be registered in order
* for this annotation to have an effect — for example, via
* {@link org.springframework.test.context.TestExecutionListeners @TestExecutionListeners}.
+ * Note, however, that the {@code EventPublishingTestExecutionListener} is registered
+ * by default.
*
* @author Frank Scheffler
* @author Sam Brannen
diff --git a/spring-test/src/main/java/org/springframework/test/context/event/annotation/package-info.java b/spring-test/src/main/java/org/springframework/test/context/event/annotation/package-info.java
index a23e6736acd1..0e0796588f2d 100644
--- a/spring-test/src/main/java/org/springframework/test/context/event/annotation/package-info.java
+++ b/spring-test/src/main/java/org/springframework/test/context/event/annotation/package-info.java
@@ -1,4 +1,4 @@
/**
- * Test event annotations for the Spring TestContext Framework.
+ * Test execution event annotations for the Spring TestContext Framework.
*/
package org.springframework.test.context.event.annotation;
diff --git a/spring-test/src/test/java/org/springframework/test/context/event/EagerTestExecutionEventPublishingTests.java b/spring-test/src/test/java/org/springframework/test/context/event/EagerTestExecutionEventPublishingTests.java
new file mode 100644
index 000000000000..fffc73d1d4bd
--- /dev/null
+++ b/spring-test/src/test/java/org/springframework/test/context/event/EagerTestExecutionEventPublishingTests.java
@@ -0,0 +1,190 @@
+/*
+ * Copyright 2002-2022 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.test.context.event;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.platform.testkit.engine.EngineTestKit;
+
+import org.springframework.context.annotation.Configuration;
+import org.springframework.core.annotation.Order;
+import org.springframework.test.context.TestContext;
+import org.springframework.test.context.TestExecutionListener;
+import org.springframework.test.context.TestExecutionListeners;
+import org.springframework.test.context.TestExecutionListeners.MergeMode;
+import org.springframework.test.context.event.annotation.AfterTestClass;
+import org.springframework.test.context.event.annotation.AfterTestExecution;
+import org.springframework.test.context.event.annotation.AfterTestMethod;
+import org.springframework.test.context.event.annotation.BeforeTestClass;
+import org.springframework.test.context.event.annotation.BeforeTestExecution;
+import org.springframework.test.context.event.annotation.BeforeTestMethod;
+import org.springframework.test.context.event.annotation.PrepareTestInstance;
+import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClass;
+
+/**
+ * Tests for the {@link EventPublishingTestExecutionListener} which verify that
+ * a {@link BeforeTestClassEvent} can be eagerly published; whereas, such an
+ * event is not published by default for the first run of a test class for a
+ * specific {@code ApplicationContext}.
+ *
+ * @author Sam Brannen
+ * @since 5.3.17
+ * @see https://github.com/spring-projects/spring-framework/issues/27757
+ */
+class EagerTestExecutionEventPublishingTests {
+
+ private static final List