From 9c24f7ba8c7555bac418e040a5ad4f5a751eb65c Mon Sep 17 00:00:00 2001 From: Sam Brannen <104798+sbrannen@users.noreply.github.com> Date: Thu, 30 Oct 2025 11:22:19 +0100 Subject: [PATCH] Document test-method scoped TestContext semantics Although gh-35680 introduced support for JUnit Jupiter's TEST_METHOD ExtensionContextScope in the SpringExtension and BeanOverrideTestExecutionListener, those were internal changes that are not directly visible by TestExecutionListener authors. However, in order to be compatible with a test-method scoped TestContext (which takes its values from the current Jupiter ExtensionContext), existing third-party TestExecutionListener implementations may need to be modified similar to how BeanOverrideTestExecutionListener was modified in commit d24a31d469. To raise awareness of how to deal with such issues, this commit documents test-method TestContext semantics for TestExecutionListener authors. Closes gh-35716 --- .../springframework/test/context/TestContext.java | 14 ++++++++++++++ .../test/context/TestExecutionListener.java | 13 +++++++++++++ 2 files changed, 27 insertions(+) diff --git a/spring-test/src/main/java/org/springframework/test/context/TestContext.java b/spring-test/src/main/java/org/springframework/test/context/TestContext.java index f3b8f447c15..b5c7ef142ad 100644 --- a/spring-test/src/main/java/org/springframework/test/context/TestContext.java +++ b/spring-test/src/main/java/org/springframework/test/context/TestContext.java @@ -98,6 +98,20 @@ public interface TestContext extends AttributeAccessor, Serializable { /** * Get the {@linkplain Class test class} for this test context. + *

Since JUnit Jupiter 5.12, if the + * {@link org.springframework.test.context.junit.jupiter.SpringExtension + * SpringExtension} is used with a {@linkplain + * org.junit.jupiter.api.extension.TestInstantiationAwareExtension.ExtensionContextScope#TEST_METHOD + * test-method scoped} {@link org.junit.jupiter.api.extension.ExtensionContext + * ExtensionContext}, the {@code Class} returned from this method may refer + * to the test class for the current {@linkplain #getTestMethod() test method}, + * which may be a {@link org.junit.jupiter.api.Nested @Nested} test class + * within the class for the {@linkplain #getTestInstance() test instance}. + * Thus, if you need consistent access to the class for the current test + * instance within an implementation of + * {@link TestExecutionListener#prepareTestInstance(TestContext)}, you should + * invoke {@code testContext.getTestInstance().getClass()} instead of + * {@code testContext.getTestClass()}. * @return the test class (never {@code null}) */ Class getTestClass(); diff --git a/spring-test/src/main/java/org/springframework/test/context/TestExecutionListener.java b/spring-test/src/main/java/org/springframework/test/context/TestExecutionListener.java index ad180d685aa..b9f9a96f4cc 100644 --- a/spring-test/src/main/java/org/springframework/test/context/TestExecutionListener.java +++ b/spring-test/src/main/java/org/springframework/test/context/TestExecutionListener.java @@ -150,6 +150,19 @@ public interface TestExecutionListener { * {@link org.springframework.test.context.junit4.rules.SpringMethodRule * SpringMethodRule}). In any case, this method must be called prior to any * framework-specific lifecycle callbacks. + *

Since JUnit Jupiter 5.12, if the + * {@link org.springframework.test.context.junit.jupiter.SpringExtension + * SpringExtension} is used with a {@linkplain + * org.junit.jupiter.api.extension.TestInstantiationAwareExtension.ExtensionContextScope#TEST_METHOD + * test-method scoped} {@link org.junit.jupiter.api.extension.ExtensionContext + * ExtensionContext}, the {@link Class} returned from + * {@link TestContext#getTestClass()} may refer to the test class for the + * current {@linkplain TestContext#getTestMethod() test method}, which may be + * a {@link org.junit.jupiter.api.Nested @Nested} test class within the class + * for the {@linkplain TestContext#getTestInstance() test instance}. Thus, if + * you need consistent access to the class for the current test instance, you + * should invoke {@code testContext.getTestInstance().getClass()} instead of + * {@code testContext.getTestClass()}. *

See the {@linkplain TestExecutionListener class-level documentation} * for details on wrapping behavior for listeners. *

The default implementation is empty. Can be overridden by