From d84bf1840886841a41967c1880d85c9cde907d44 Mon Sep 17 00:00:00 2001 From: Sam Brannen <104798+sbrannen@users.noreply.github.com> Date: Sat, 28 Jun 2025 11:18:44 +0200 Subject: [PATCH] Upgrade to JUnit 6.0 RC3 See gh-35124 --- build.gradle | 2 +- framework-platform/framework-platform.gradle | 2 +- .../CompileWithForkedClassLoaderExtension.java | 15 ++++++++------- spring-test/spring-test.gradle | 3 +++ .../context/junit/jupiter/SpringExtension.java | 7 +++---- .../test/context/aot/AotIntegrationTests.java | 10 +++++----- .../cache/ContextFailureThresholdTests.java | 18 +++++++++--------- .../cache/UnusedContextsIntegrationTests.java | 9 +-------- ...EagerTestExecutionEventPublishingTests.java | 6 +++--- .../jdbc/GeneratedDatabaseNamesTests.java | 9 ++------- .../jupiter/DisabledIfConditionTests.java | 2 +- .../web/reactive/resource/GzipSupport.java | 2 +- .../web/servlet/resource/GzipSupport.java | 2 +- 13 files changed, 39 insertions(+), 48 deletions(-) diff --git a/build.gradle b/build.gradle index 8f6ca47040..df586e1b06 100644 --- a/build.gradle +++ b/build.gradle @@ -75,7 +75,7 @@ configure([rootProject] + javaProjects) { project -> "https://hc.apache.org/httpcomponents-client-5.5.x/current/httpclient5/apidocs/", "https://projectreactor.io/docs/test/release/api/", "https://junit.org/junit4/javadoc/4.13.2/", - "https://docs.junit.org/5.13.4/api/", + "https://docs.junit.org/6.0.0-RC3/api/", "https://www.reactive-streams.org/reactive-streams-1.0.3-javadoc/", //"https://javadoc.io/static/io.rsocket/rsocket-core/1.1.1/", "https://r2dbc.io/spec/1.0.0.RELEASE/api/", diff --git a/framework-platform/framework-platform.gradle b/framework-platform/framework-platform.gradle index 1b8ddebf99..626f43b658 100644 --- a/framework-platform/framework-platform.gradle +++ b/framework-platform/framework-platform.gradle @@ -19,7 +19,7 @@ dependencies { api(platform("org.eclipse.jetty.ee11:jetty-ee11-bom:12.1.1")) api(platform("org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.10.2")) api(platform("org.jetbrains.kotlinx:kotlinx-serialization-bom:1.9.0")) - api(platform("org.junit:junit-bom:5.13.4")) + api(platform("org.junit:junit-bom:6.0.0-RC3")) api(platform("org.mockito:mockito-bom:5.19.0")) api(platform("tools.jackson:jackson-bom:3.0.0-rc10")) diff --git a/spring-core-test/src/main/java/org/springframework/core/test/tools/CompileWithForkedClassLoaderExtension.java b/spring-core-test/src/main/java/org/springframework/core/test/tools/CompileWithForkedClassLoaderExtension.java index f103b2e2fd..f442ca0f53 100644 --- a/spring-core-test/src/main/java/org/springframework/core/test/tools/CompileWithForkedClassLoaderExtension.java +++ b/spring-core-test/src/main/java/org/springframework/core/test/tools/CompileWithForkedClassLoaderExtension.java @@ -18,6 +18,7 @@ package org.springframework.core.test.tools; import java.lang.reflect.Method; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.extension.ExtensionContext; import org.junit.jupiter.api.extension.InvocationInterceptor; import org.junit.jupiter.api.extension.ReflectiveInvocationContext; @@ -44,7 +45,7 @@ import static org.junit.platform.launcher.EngineFilter.includeEngines; class CompileWithForkedClassLoaderExtension implements InvocationInterceptor { @Override - public void interceptBeforeAllMethod(Invocation invocation, + public void interceptBeforeAllMethod(Invocation<@Nullable Void> invocation, ReflectiveInvocationContext invocationContext, ExtensionContext extensionContext) throws Throwable { @@ -52,7 +53,7 @@ class CompileWithForkedClassLoaderExtension implements InvocationInterceptor { } @Override - public void interceptBeforeEachMethod(Invocation invocation, + public void interceptBeforeEachMethod(Invocation<@Nullable Void> invocation, ReflectiveInvocationContext invocationContext, ExtensionContext extensionContext) throws Throwable { @@ -60,7 +61,7 @@ class CompileWithForkedClassLoaderExtension implements InvocationInterceptor { } @Override - public void interceptAfterEachMethod(Invocation invocation, + public void interceptAfterEachMethod(Invocation<@Nullable Void> invocation, ReflectiveInvocationContext invocationContext, ExtensionContext extensionContext) throws Throwable { @@ -68,7 +69,7 @@ class CompileWithForkedClassLoaderExtension implements InvocationInterceptor { } @Override - public void interceptAfterAllMethod(Invocation invocation, + public void interceptAfterAllMethod(Invocation<@Nullable Void> invocation, ReflectiveInvocationContext invocationContext, ExtensionContext extensionContext) throws Throwable { @@ -76,7 +77,7 @@ class CompileWithForkedClassLoaderExtension implements InvocationInterceptor { } @Override - public void interceptTestMethod(Invocation invocation, + public void interceptTestMethod(Invocation<@Nullable Void> invocation, ReflectiveInvocationContext invocationContext, ExtensionContext extensionContext) throws Throwable { @@ -84,13 +85,13 @@ class CompileWithForkedClassLoaderExtension implements InvocationInterceptor { () -> runTestWithModifiedClassPath(invocationContext, extensionContext)); } - private void intercept(Invocation invocation, ExtensionContext extensionContext) + private void intercept(Invocation<@Nullable Void> invocation, ExtensionContext extensionContext) throws Throwable { intercept(invocation, extensionContext, Action.NONE); } - private void intercept(Invocation invocation, ExtensionContext extensionContext, + private void intercept(Invocation<@Nullable Void> invocation, ExtensionContext extensionContext, Action action) throws Throwable { if (isUsingForkedClassPathLoader(extensionContext)) { diff --git a/spring-test/spring-test.gradle b/spring-test/spring-test.gradle index e1200b96de..16400732fc 100644 --- a/spring-test/spring-test.gradle +++ b/spring-test/spring-test.gradle @@ -110,6 +110,9 @@ test { // `include` test filters and system properties are configured in // org.springframework.build.TestConventions in buildSrc. filter.excludeTestsMatching("*TestCase") + // Override critical severity defined in TestConventions, since spring-test + // relies on the Vintage test engine for JUnit 4 support. + systemProperty("junit.platform.discovery.issue.severity.critical", "WARNING") // Optionally configure Java Util Logging for the JUnit Platform. // systemProperty("java.util.logging.manager", "org.apache.logging.log4j.jul.LogManager") } diff --git a/spring-test/src/main/java/org/springframework/test/context/junit/jupiter/SpringExtension.java b/spring-test/src/main/java/org/springframework/test/context/junit/jupiter/SpringExtension.java index 354833f73b..7076787737 100644 --- a/spring-test/src/main/java/org/springframework/test/context/junit/jupiter/SpringExtension.java +++ b/spring-test/src/main/java/org/springframework/test/context/junit/jupiter/SpringExtension.java @@ -169,7 +169,7 @@ public class SpringExtension implements BeforeAllCallback, AfterAllCallback, Tes // re-validate all methods for the same test class multiple times. Store store = context.getStore(AUTOWIRED_VALIDATION_NAMESPACE); - String errorMessage = store.getOrComputeIfAbsent(context.getRequiredTestClass(), testClass -> { + String errorMessage = store.computeIfAbsent(context.getRequiredTestClass(), testClass -> { Method[] methodsWithErrors = ReflectionUtils.getUniqueDeclaredMethods(testClass, autowiredTestOrLifecycleMethodFilter); return (methodsWithErrors.length == 0 ? NO_VIOLATIONS_DETECTED : @@ -197,7 +197,7 @@ public class SpringExtension implements BeforeAllCallback, AfterAllCallback, Tes // re-validate the configuration for the same test class multiple times. Store store = context.getStore(RECORD_APPLICATION_EVENTS_VALIDATION_NAMESPACE); - String errorMessage = store.getOrComputeIfAbsent(context.getRequiredTestClass(), testClass -> { + String errorMessage = store.computeIfAbsent(context.getRequiredTestClass(), testClass -> { boolean recording = TestContextAnnotationUtils.hasAnnotation(testClass, RecordApplicationEvents.class); if (!recording) { return NO_VIOLATIONS_DETECTED; @@ -358,7 +358,7 @@ public class SpringExtension implements BeforeAllCallback, AfterAllCallback, Tes Assert.notNull(context, "ExtensionContext must not be null"); Class testClass = context.getRequiredTestClass(); Store store = getStore(context); - return store.getOrComputeIfAbsent(testClass, TestContextManager::new, TestContextManager.class); + return store.computeIfAbsent(testClass, TestContextManager::new, TestContextManager.class); } private static Store getStore(ExtensionContext context) { @@ -372,7 +372,6 @@ public class SpringExtension implements BeforeAllCallback, AfterAllCallback, Tes * the supplied {@link TestContextManager}. * @since 6.1 */ - @SuppressWarnings("NullAway") // org.junit.jupiter.api.extension.ExecutableInvoker is not null marked private static void registerMethodInvoker(TestContextManager testContextManager, ExtensionContext context) { testContextManager.getTestContext().setMethodInvoker(context.getExecutableInvoker()::invoke); } diff --git a/spring-test/src/test/java/org/springframework/test/context/aot/AotIntegrationTests.java b/spring-test/src/test/java/org/springframework/test/context/aot/AotIntegrationTests.java index aba018c35c..386ad48c58 100644 --- a/spring-test/src/test/java/org/springframework/test/context/aot/AotIntegrationTests.java +++ b/spring-test/src/test/java/org/springframework/test/context/aot/AotIntegrationTests.java @@ -56,7 +56,7 @@ import org.springframework.test.context.aot.samples.basic.DisabledInAotRuntimeMe import static org.assertj.core.api.Assertions.assertThat; import static org.junit.platform.engine.discovery.ClassNameFilter.includeClassNamePatterns; -import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClass; +import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClasses; import static org.junit.platform.launcher.TagFilter.excludeTags; /** @@ -205,11 +205,11 @@ class AotIntegrationTests extends AbstractAotTests { try { System.setProperty(AotDetector.AOT_ENABLED, "true"); - LauncherDiscoveryRequestBuilder builder = LauncherDiscoveryRequestBuilder.request() + LauncherDiscoveryRequest request = LauncherDiscoveryRequestBuilder.request() + .selectors(selectClasses(testClasses)) .filters(includeClassNamePatterns(".*Tests?$")) - .filters(excludeTags("failing-test-case")); - testClasses.forEach(testClass -> builder.selectors(selectClass(testClass))); - LauncherDiscoveryRequest request = builder.build(); + .filters(excludeTags("failing-test-case")) + .build(); SummaryGeneratingListener listener = new SummaryGeneratingListener(); LauncherFactory.create().execute(request, listener); TestExecutionSummary summary = listener.getSummary(); diff --git a/spring-test/src/test/java/org/springframework/test/context/cache/ContextFailureThresholdTests.java b/spring-test/src/test/java/org/springframework/test/context/cache/ContextFailureThresholdTests.java index 77c4b5462c..2cdab2addc 100644 --- a/spring-test/src/test/java/org/springframework/test/context/cache/ContextFailureThresholdTests.java +++ b/spring-test/src/test/java/org/springframework/test/context/cache/ContextFailureThresholdTests.java @@ -31,7 +31,7 @@ import org.springframework.test.context.junit.jupiter.SpringJUnitConfig; import org.springframework.test.context.support.DependencyInjectionTestExecutionListener; import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClass; +import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClasses; import static org.springframework.test.context.CacheAwareContextLoaderDelegate.CONTEXT_FAILURE_THRESHOLD_PROPERTY_NAME; import static org.springframework.test.context.CacheAwareContextLoaderDelegate.DEFAULT_CONTEXT_FAILURE_THRESHOLD; import static org.springframework.test.context.cache.ContextCacheTestUtils.assertContextCacheStatistics; @@ -85,14 +85,14 @@ class ContextFailureThresholdTests { } private static void runTests() { - EngineTestKit.engine("junit-jupiter")// - .selectors(// - selectClass(PassingTestCase.class), // 3 passing - selectClass(FailingConfigTestCase.class), // 3 failing - selectClass(SharedFailingConfigTestCase.class) // 3 failing - )// - .execute()// - .testEvents()// + EngineTestKit.engine("junit-jupiter") + .selectors(selectClasses( + PassingTestCase.class, // 3 passing + FailingConfigTestCase.class, // 3 failing + SharedFailingConfigTestCase.class // 3 failing + )) + .execute() + .testEvents() .assertStatistics(stats -> stats.started(9).succeeded(3).failed(6)); assertContextCacheStatistics(1, 2, (1 + 3 + 3)); } diff --git a/spring-test/src/test/java/org/springframework/test/context/cache/UnusedContextsIntegrationTests.java b/spring-test/src/test/java/org/springframework/test/context/cache/UnusedContextsIntegrationTests.java index 49dac4c34a..1df14d11a6 100644 --- a/spring-test/src/test/java/org/springframework/test/context/cache/UnusedContextsIntegrationTests.java +++ b/spring-test/src/test/java/org/springframework/test/context/cache/UnusedContextsIntegrationTests.java @@ -16,8 +16,6 @@ package org.springframework.test.context.cache; -import java.util.Arrays; - import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.ClassOrderer; @@ -25,8 +23,6 @@ import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Order; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestClassOrder; -import org.junit.platform.engine.discovery.ClassSelector; -import org.junit.platform.engine.discovery.DiscoverySelectors; import org.junit.platform.testkit.engine.EngineTestKit; import org.springframework.beans.factory.annotation.Value; @@ -38,6 +34,7 @@ import org.springframework.test.context.TestPropertySource; import org.springframework.test.context.junit.jupiter.SpringJUnitConfig; import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClasses; import static org.springframework.test.context.NestedTestConfiguration.EnclosingConfiguration.INHERIT; import static org.springframework.test.context.NestedTestConfiguration.EnclosingConfiguration.OVERRIDE; @@ -209,10 +206,6 @@ class UnusedContextsIntegrationTests { .assertStatistics(stats -> stats.started(expectedTestCount).succeeded(expectedTestCount)); } - private static ClassSelector[] selectClasses(Class... classes) { - return Arrays.stream(classes).map(DiscoverySelectors::selectClass).toArray(ClassSelector[]::new); - } - @SpringJUnitConfig(EventTracker.class) @ContextCustomizerFactories(DisplayNameCustomizerFactory.class) 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 index fc4eab1be8..4b589903be 100644 --- 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 @@ -40,7 +40,7 @@ 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; +import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClasses; /** * Tests for the {@link EventPublishingTestExecutionListener} which verify that @@ -65,7 +65,7 @@ class EagerTestExecutionEventPublishingTests { @Test void beforeTestClassEventIsNotPublishedByDefaultForFirstTestClass() { EngineTestKit.engine("junit-jupiter")// - .selectors(selectClass(LazyTestCase1.class), selectClass(LazyTestCase2.class))// + .selectors(selectClasses(LazyTestCase1.class, LazyTestCase2.class))// .execute()// .testEvents()// .assertStatistics(stats -> stats.started(2).succeeded(2).failed(0)); @@ -93,7 +93,7 @@ class EagerTestExecutionEventPublishingTests { @Test void beforeTestClassEventIsPublishedForAllTestClassesIfCustomListenerEagerlyLoadsContext() { EngineTestKit.engine("junit-jupiter")// - .selectors(selectClass(EagerTestCase1.class), selectClass(EagerTestCase2.class))// + .selectors(selectClasses(EagerTestCase1.class, EagerTestCase2.class))// .execute()// .testEvents()// .assertStatistics(stats -> stats.started(2).succeeded(2).failed(0)); diff --git a/spring-test/src/test/java/org/springframework/test/context/jdbc/GeneratedDatabaseNamesTests.java b/spring-test/src/test/java/org/springframework/test/context/jdbc/GeneratedDatabaseNamesTests.java index bdf3377803..49c0d7656e 100644 --- a/spring-test/src/test/java/org/springframework/test/context/jdbc/GeneratedDatabaseNamesTests.java +++ b/spring-test/src/test/java/org/springframework/test/context/jdbc/GeneratedDatabaseNamesTests.java @@ -29,7 +29,7 @@ import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit.jupiter.SpringExtension; import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClass; +import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClasses; /** * Test suite to investigate claims raised in @@ -66,12 +66,7 @@ class GeneratedDatabaseNamesTests { @Test void runTestsWithGeneratedDatabaseNames() { EngineTestKit.engine("junit-jupiter") - .selectors( - selectClass(TestClass1A.class), - selectClass(TestClass1B.class), - selectClass(TestClass2A.class), - selectClass(TestClass2B.class) - ) + .selectors(selectClasses(TestClass1A.class, TestClass1B.class, TestClass2A.class, TestClass2B.class)) .execute() .testEvents() .assertStatistics(stats -> stats.started(4).succeeded(4).failed(0)); diff --git a/spring-test/src/test/java/org/springframework/test/context/junit/jupiter/DisabledIfConditionTests.java b/spring-test/src/test/java/org/springframework/test/context/junit/jupiter/DisabledIfConditionTests.java index 109c96d069..579274fe6b 100644 --- a/spring-test/src/test/java/org/springframework/test/context/junit/jupiter/DisabledIfConditionTests.java +++ b/spring-test/src/test/java/org/springframework/test/context/junit/jupiter/DisabledIfConditionTests.java @@ -112,7 +112,7 @@ class DisabledIfConditionTests { Class testClass = SpringTestCase.class; Method method = ReflectionUtils.findMethod(getClass(), methodName); Store store = mock(); - given(store.getOrComputeIfAbsent(any(), any(), any())).willReturn(new TestContextManager(testClass)); + given(store.computeIfAbsent(any(), any(), any())).willReturn(new TestContextManager(testClass)); ExtensionContext extensionContext = mock(); given(extensionContext.getTestClass()).willReturn(Optional.of(testClass)); diff --git a/spring-webflux/src/test/java/org/springframework/web/reactive/resource/GzipSupport.java b/spring-webflux/src/test/java/org/springframework/web/reactive/resource/GzipSupport.java index 6846108501..bbbfa39460 100644 --- a/spring-webflux/src/test/java/org/springframework/web/reactive/resource/GzipSupport.java +++ b/spring-webflux/src/test/java/org/springframework/web/reactive/resource/GzipSupport.java @@ -55,7 +55,7 @@ class GzipSupport implements ParameterResolver { @Override public Object resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext) { - return getStore(extensionContext).getOrComputeIfAbsent(GzippedFiles.class); + return getStore(extensionContext).computeIfAbsent(GzippedFiles.class); } private Store getStore(ExtensionContext extensionContext) { diff --git a/spring-webmvc/src/test/java/org/springframework/web/servlet/resource/GzipSupport.java b/spring-webmvc/src/test/java/org/springframework/web/servlet/resource/GzipSupport.java index 7fe45d7e7b..16e3e8062b 100644 --- a/spring-webmvc/src/test/java/org/springframework/web/servlet/resource/GzipSupport.java +++ b/spring-webmvc/src/test/java/org/springframework/web/servlet/resource/GzipSupport.java @@ -55,7 +55,7 @@ class GzipSupport implements ParameterResolver { @Override public Object resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext) { - return getStore(extensionContext).getOrComputeIfAbsent(GzippedFiles.class); + return getStore(extensionContext).computeIfAbsent(GzippedFiles.class); } private Store getStore(ExtensionContext extensionContext) {