diff --git a/config/checkstyle/import-control.xml b/config/checkstyle/import-control.xml
index 1674da76c3e..2d591aaaa22 100644
--- a/config/checkstyle/import-control.xml
+++ b/config/checkstyle/import-control.xml
@@ -109,6 +109,10 @@
+
+
+
+
diff --git a/module/spring-boot-web-server-test/src/main/java/org/springframework/boot/web/server/test/client/reactive/WebTestClientBuilderCustomizer.java b/core/spring-boot-test/src/main/java/org/springframework/boot/test/web/reactive/client/WebTestClientBuilderCustomizer.java
similarity index 79%
rename from module/spring-boot-web-server-test/src/main/java/org/springframework/boot/web/server/test/client/reactive/WebTestClientBuilderCustomizer.java
rename to core/spring-boot-test/src/main/java/org/springframework/boot/test/web/reactive/client/WebTestClientBuilderCustomizer.java
index a3f911a3bb2..7cd12f2da2b 100644
--- a/module/spring-boot-web-server-test/src/main/java/org/springframework/boot/web/server/test/client/reactive/WebTestClientBuilderCustomizer.java
+++ b/core/spring-boot-test/src/main/java/org/springframework/boot/test/web/reactive/client/WebTestClientBuilderCustomizer.java
@@ -14,14 +14,17 @@
* limitations under the License.
*/
-package org.springframework.boot.web.server.test.client.reactive;
+package org.springframework.boot.test.web.reactive.client;
+import org.springframework.context.ApplicationContext;
import org.springframework.test.web.reactive.server.WebTestClient;
import org.springframework.test.web.reactive.server.WebTestClient.Builder;
/**
* A customizer that can be implemented by beans wishing to customize the {@link Builder}
- * to fine-tine its auto-configuration before a {@link WebTestClient} is created.
+ * to fine-tune its auto-configuration before a {@link WebTestClient} is created.
+ * Implementations can be registered in the {@link ApplicationContext} or
+ * {@code spring.factories}.
*
* @author Andy Wilkinson
* @since 4.0.0
diff --git a/module/spring-boot-web-server-test/src/main/java/org/springframework/boot/web/server/test/client/reactive/WebTestClientContextCustomizer.java b/core/spring-boot-test/src/main/java/org/springframework/boot/test/web/reactive/client/WebTestClientContextCustomizer.java
similarity index 56%
rename from module/spring-boot-web-server-test/src/main/java/org/springframework/boot/web/server/test/client/reactive/WebTestClientContextCustomizer.java
rename to core/spring-boot-test/src/main/java/org/springframework/boot/test/web/reactive/client/WebTestClientContextCustomizer.java
index cb342f31a37..d6729722357 100644
--- a/module/spring-boot-web-server-test/src/main/java/org/springframework/boot/web/server/test/client/reactive/WebTestClientContextCustomizer.java
+++ b/core/spring-boot-test/src/main/java/org/springframework/boot/test/web/reactive/client/WebTestClientContextCustomizer.java
@@ -14,11 +14,11 @@
* limitations under the License.
*/
-package org.springframework.boot.web.server.test.client.reactive;
+package org.springframework.boot.test.web.reactive.client;
-import java.util.Collection;
+import java.util.ArrayList;
+import java.util.List;
-import jakarta.servlet.ServletContext;
import org.jspecify.annotations.Nullable;
import org.springframework.aot.AotDetector;
@@ -28,31 +28,26 @@ import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.ListableBeanFactory;
-import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.beans.factory.support.RootBeanDefinition;
-import org.springframework.boot.WebApplicationType;
-import org.springframework.boot.http.codec.CodecCustomizer;
import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.boot.web.server.reactive.AbstractReactiveWebServerFactory;
+import org.springframework.boot.test.http.server.BaseUrl;
+import org.springframework.boot.test.http.server.BaseUrlProviders;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.ConfigurationClassPostProcessor;
import org.springframework.core.Ordered;
+import org.springframework.core.io.support.SpringFactoriesLoader;
+import org.springframework.core.io.support.SpringFactoriesLoader.ArgumentResolver;
import org.springframework.test.context.ContextCustomizer;
import org.springframework.test.context.MergedContextConfiguration;
import org.springframework.test.context.TestContextAnnotationUtils;
import org.springframework.test.web.reactive.server.WebTestClient;
import org.springframework.util.Assert;
-import org.springframework.util.ClassUtils;
-import org.springframework.util.CollectionUtils;
-import org.springframework.util.StringUtils;
-import org.springframework.web.context.WebApplicationContext;
-import org.springframework.web.reactive.function.client.ExchangeStrategies;
/**
* {@link ContextCustomizer} for {@link WebTestClient}.
@@ -61,13 +56,6 @@ import org.springframework.web.reactive.function.client.ExchangeStrategies;
*/
class WebTestClientContextCustomizer implements ContextCustomizer {
- private static final boolean codecCustomizerPresent;
-
- static {
- ClassLoader loader = WebTestClientContextCustomizerFactory.class.getClassLoader();
- codecCustomizerPresent = ClassUtils.isPresent("org.springframework.boot.http.codec.CodecCustomizer", loader);
- }
-
@Override
public void customizeContext(ConfigurableApplicationContext context, MergedContextConfiguration mergedConfig) {
if (AotDetector.useGeneratedArtifacts()) {
@@ -111,8 +99,7 @@ class WebTestClientContextCustomizer implements ContextCustomizer {
*/
static class WebTestClientRegistrar implements BeanDefinitionRegistryPostProcessor, Ordered, BeanFactoryAware {
- @SuppressWarnings("NullAway.Init")
- private BeanFactory beanFactory;
+ private @Nullable BeanFactory beanFactory;
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
@@ -126,7 +113,7 @@ class WebTestClientContextCustomizer implements ContextCustomizer {
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
- if (AotDetector.useGeneratedArtifacts()) {
+ if (this.beanFactory == null || AotDetector.useGeneratedArtifacts()) {
return;
}
if (BeanFactoryUtils.beanNamesForTypeIncludingAncestors((ListableBeanFactory) this.beanFactory,
@@ -134,7 +121,6 @@ class WebTestClientContextCustomizer implements ContextCustomizer {
registry.registerBeanDefinition(WebTestClient.class.getName(),
new RootBeanDefinition(WebTestClientFactory.class));
}
-
}
@Override
@@ -148,15 +134,10 @@ class WebTestClientContextCustomizer implements ContextCustomizer {
*/
public static class WebTestClientFactory implements FactoryBean, ApplicationContextAware {
- @SuppressWarnings("NullAway.Init")
- private ApplicationContext applicationContext;
+ private @Nullable ApplicationContext applicationContext;
private @Nullable WebTestClient object;
- private static final String SERVLET_APPLICATION_CONTEXT_CLASS = "org.springframework.web.context.WebApplicationContext";
-
- private static final String REACTIVE_APPLICATION_CONTEXT_CLASS = "org.springframework.boot.web.context.reactive.ReactiveWebApplicationContext";
-
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
@@ -181,87 +162,29 @@ class WebTestClientContextCustomizer implements ContextCustomizer {
}
private WebTestClient createWebTestClient() {
- boolean sslEnabled = isSslEnabled(this.applicationContext);
- String port = this.applicationContext.getEnvironment().getProperty("local.server.port", "8080");
- String baseUrl = getBaseUrl(sslEnabled, port);
+ Assert.state(this.applicationContext != null, "ApplicationContext not injected");
WebTestClient.Builder builder = WebTestClient.bindToServer();
customizeWebTestClientBuilder(builder, this.applicationContext);
- if (codecCustomizerPresent) {
- WebTestClientCodecCustomizer.customizeWebTestClientCodecs(builder, this.applicationContext);
- }
- return builder.baseUrl(baseUrl).build();
- }
-
- private String getBaseUrl(boolean sslEnabled, String port) {
- String basePath = deduceBasePath();
- String pathSegment = (StringUtils.hasText(basePath)) ? basePath : "";
- return (sslEnabled ? "https" : "http") + "://localhost:" + port + pathSegment;
- }
-
- private @Nullable String deduceBasePath() {
- WebApplicationType webApplicationType = deduceFromApplicationContext(this.applicationContext.getClass());
- if (webApplicationType == WebApplicationType.REACTIVE) {
- return this.applicationContext.getEnvironment().getProperty("spring.webflux.base-path");
- }
- else if (webApplicationType == WebApplicationType.SERVLET) {
- ServletContext servletContext = ((WebApplicationContext) this.applicationContext).getServletContext();
- Assert.state(servletContext != null, "'servletContext' must not be null");
- return servletContext.getContextPath();
- }
- return null;
- }
-
- static WebApplicationType deduceFromApplicationContext(Class> applicationContextClass) {
- if (isAssignable(SERVLET_APPLICATION_CONTEXT_CLASS, applicationContextClass)) {
- return WebApplicationType.SERVLET;
- }
- if (isAssignable(REACTIVE_APPLICATION_CONTEXT_CLASS, applicationContextClass)) {
- return WebApplicationType.REACTIVE;
- }
- return WebApplicationType.NONE;
- }
-
- private static boolean isAssignable(String target, Class> type) {
- try {
- return ClassUtils.resolveClassName(target, null).isAssignableFrom(type);
- }
- catch (Throwable ex) {
- return false;
- }
- }
-
- private boolean isSslEnabled(ApplicationContext context) {
- try {
- AbstractReactiveWebServerFactory webServerFactory = context
- .getBean(AbstractReactiveWebServerFactory.class);
- return webServerFactory.getSsl() != null && webServerFactory.getSsl().isEnabled();
- }
- catch (NoSuchBeanDefinitionException ex) {
- return false;
+ BaseUrl baseUrl = new BaseUrlProviders(this.applicationContext).getBaseUrl();
+ if (baseUrl != null) {
+ builder.baseUrl(baseUrl.resolve());
}
+ return builder.build();
}
private void customizeWebTestClientBuilder(WebTestClient.Builder clientBuilder, ApplicationContext context) {
- for (WebTestClientBuilderCustomizer customizer : context
- .getBeansOfType(WebTestClientBuilderCustomizer.class)
- .values()) {
- customizer.customize(clientBuilder);
- }
- }
-
- private static final class WebTestClientCodecCustomizer {
-
- private static void customizeWebTestClientCodecs(WebTestClient.Builder clientBuilder,
- ApplicationContext context) {
- Collection codecCustomizers = context.getBeansOfType(CodecCustomizer.class).values();
- if (!CollectionUtils.isEmpty(codecCustomizers)) {
- clientBuilder.exchangeStrategies(ExchangeStrategies.builder()
- .codecs((codecs) -> codecCustomizers
- .forEach((codecCustomizer) -> codecCustomizer.customize(codecs)))
- .build());
- }
- }
-
+ Assert.state(this.applicationContext != null, "ApplicationContext not injected");
+ getWebTestClientBuilderCustomizers(this.applicationContext)
+ .forEach((customizer) -> customizer.customize(clientBuilder));
+ }
+
+ private List getWebTestClientBuilderCustomizers(ApplicationContext context) {
+ List customizers = new ArrayList<>();
+ SpringFactoriesLoader.forDefaultResourceLocation(context.getClassLoader())
+ .load(WebTestClientBuilderCustomizer.class, ArgumentResolver.of(ApplicationContext.class, context))
+ .forEach(customizers::add);
+ context.getBeansOfType(WebTestClientBuilderCustomizer.class).values().forEach(customizers::add);
+ return customizers;
}
}
diff --git a/module/spring-boot-web-server-test/src/main/java/org/springframework/boot/web/server/test/client/reactive/WebTestClientContextCustomizerFactory.java b/core/spring-boot-test/src/main/java/org/springframework/boot/test/web/reactive/client/WebTestClientContextCustomizerFactory.java
similarity index 96%
rename from module/spring-boot-web-server-test/src/main/java/org/springframework/boot/web/server/test/client/reactive/WebTestClientContextCustomizerFactory.java
rename to core/spring-boot-test/src/main/java/org/springframework/boot/test/web/reactive/client/WebTestClientContextCustomizerFactory.java
index b9599400273..90cf1869805 100644
--- a/module/spring-boot-web-server-test/src/main/java/org/springframework/boot/web/server/test/client/reactive/WebTestClientContextCustomizerFactory.java
+++ b/core/spring-boot-test/src/main/java/org/springframework/boot/test/web/reactive/client/WebTestClientContextCustomizerFactory.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package org.springframework.boot.web.server.test.client.reactive;
+package org.springframework.boot.test.web.reactive.client;
import java.util.List;
diff --git a/module/spring-boot-web-server-test/src/main/java/org/springframework/boot/web/server/test/client/reactive/package-info.java b/core/spring-boot-test/src/main/java/org/springframework/boot/test/web/reactive/client/package-info.java
similarity index 92%
rename from module/spring-boot-web-server-test/src/main/java/org/springframework/boot/web/server/test/client/reactive/package-info.java
rename to core/spring-boot-test/src/main/java/org/springframework/boot/test/web/reactive/client/package-info.java
index f5522d65012..76a491a8095 100644
--- a/module/spring-boot-web-server-test/src/main/java/org/springframework/boot/web/server/test/client/reactive/package-info.java
+++ b/core/spring-boot-test/src/main/java/org/springframework/boot/test/web/reactive/client/package-info.java
@@ -19,6 +19,6 @@
* {@link org.springframework.test.web.reactive.server.WebTestClient}.
*/
@NullMarked
-package org.springframework.boot.web.server.test.client.reactive;
+package org.springframework.boot.test.web.reactive.client;
import org.jspecify.annotations.NullMarked;
diff --git a/core/spring-boot-test/src/main/resources/META-INF/spring.factories b/core/spring-boot-test/src/main/resources/META-INF/spring.factories
index 5be7efde86a..fa085a63a02 100644
--- a/core/spring-boot-test/src/main/resources/META-INF/spring.factories
+++ b/core/spring-boot-test/src/main/resources/META-INF/spring.factories
@@ -4,7 +4,8 @@ org.springframework.boot.test.context.ImportsContextCustomizerFactory,\
org.springframework.boot.test.context.PropertyMappingContextCustomizerFactory,\
org.springframework.boot.test.context.filter.ExcludeFilterContextCustomizerFactory,\
org.springframework.boot.test.context.filter.annotation.TypeExcludeFiltersContextCustomizerFactory,\
-org.springframework.boot.test.json.DuplicateJsonObjectContextCustomizerFactory
+org.springframework.boot.test.json.DuplicateJsonObjectContextCustomizerFactory,\
+org.springframework.boot.test.web.reactive.client.WebTestClientContextCustomizerFactory
# Application Context Initializers
org.springframework.context.ApplicationContextInitializer=\
diff --git a/documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/testing/springbootapplications/autoconfiguredspringrestdocs/withwebtestclient/MyWebTestClientBuilderCustomizerConfiguration.java b/documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/testing/springbootapplications/autoconfiguredspringrestdocs/withwebtestclient/MyWebTestClientBuilderCustomizerConfiguration.java
index 79718c1d351..9ba584cf2ce 100644
--- a/documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/testing/springbootapplications/autoconfiguredspringrestdocs/withwebtestclient/MyWebTestClientBuilderCustomizerConfiguration.java
+++ b/documentation/spring-boot-docs/src/main/java/org/springframework/boot/docs/testing/springbootapplications/autoconfiguredspringrestdocs/withwebtestclient/MyWebTestClientBuilderCustomizerConfiguration.java
@@ -17,7 +17,7 @@
package org.springframework.boot.docs.testing.springbootapplications.autoconfiguredspringrestdocs.withwebtestclient;
import org.springframework.boot.test.context.TestConfiguration;
-import org.springframework.boot.web.server.test.client.reactive.WebTestClientBuilderCustomizer;
+import org.springframework.boot.test.web.reactive.client.WebTestClientBuilderCustomizer;
import org.springframework.context.annotation.Bean;
import static org.springframework.restdocs.webtestclient.WebTestClientRestDocumentation.document;
diff --git a/documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/testing/springbootapplications/autoconfiguredspringrestdocs/withwebtestclient/MyWebTestClientBuilderCustomizerConfiguration.kt b/documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/testing/springbootapplications/autoconfiguredspringrestdocs/withwebtestclient/MyWebTestClientBuilderCustomizerConfiguration.kt
index b7f99bd9524..30825160813 100644
--- a/documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/testing/springbootapplications/autoconfiguredspringrestdocs/withwebtestclient/MyWebTestClientBuilderCustomizerConfiguration.kt
+++ b/documentation/spring-boot-docs/src/main/kotlin/org/springframework/boot/docs/testing/springbootapplications/autoconfiguredspringrestdocs/withwebtestclient/MyWebTestClientBuilderCustomizerConfiguration.kt
@@ -17,7 +17,7 @@
package org.springframework.boot.docs.testing.springbootapplications.autoconfiguredspringrestdocs.withwebtestclient
import org.springframework.boot.test.context.TestConfiguration
-import org.springframework.boot.web.server.test.client.reactive.WebTestClientBuilderCustomizer
+import org.springframework.boot.test.web.reactive.client.WebTestClientBuilderCustomizer
import org.springframework.context.annotation.Bean
import org.springframework.restdocs.webtestclient.WebTestClientRestDocumentation
import org.springframework.test.web.reactive.server.WebTestClient
diff --git a/integration-test/spring-boot-test-integration-tests/build.gradle b/integration-test/spring-boot-test-integration-tests/build.gradle
new file mode 100644
index 00000000000..014c524c6ba
--- /dev/null
+++ b/integration-test/spring-boot-test-integration-tests/build.gradle
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2012-present 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.
+ */
+
+
+plugins {
+ id "java-library"
+}
+
+description = "Spring Boot Test Integration Tests"
+
+dependencies {
+ testImplementation(project(":core:spring-boot-test"))
+ testImplementation(project(":test-support:spring-boot-test-support"))
+ testImplementation(project(":module:spring-boot-http-codec"))
+ testImplementation(project(":module:spring-boot-tomcat"))
+ testImplementation(project(":module:spring-boot-web-server"))
+ testImplementation("io.projectreactor.netty:reactor-netty-http")
+ testImplementation("org.springframework:spring-webmvc")
+ testImplementation("org.springframework:spring-webflux")
+}
diff --git a/module/spring-boot-web-server-test/src/test/java/org/springframework/boot/web/server/test/client/reactive/NoWebTestClientBeanChecker.java b/integration-test/spring-boot-test-integration-tests/src/test/java/org/springframework/boot/test/web/reactive/client/NoWebTestClientBeanChecker.java
similarity index 96%
rename from module/spring-boot-web-server-test/src/test/java/org/springframework/boot/web/server/test/client/reactive/NoWebTestClientBeanChecker.java
rename to integration-test/spring-boot-test-integration-tests/src/test/java/org/springframework/boot/test/web/reactive/client/NoWebTestClientBeanChecker.java
index 89c55e62c48..039485bf5e1 100644
--- a/module/spring-boot-web-server-test/src/test/java/org/springframework/boot/web/server/test/client/reactive/NoWebTestClientBeanChecker.java
+++ b/integration-test/spring-boot-test-integration-tests/src/test/java/org/springframework/boot/test/web/reactive/client/NoWebTestClientBeanChecker.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package org.springframework.boot.web.server.test.client.reactive;
+package org.springframework.boot.test.web.reactive.client;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
diff --git a/module/spring-boot-web-server-test/src/test/java/org/springframework/boot/web/server/test/client/reactive/WebTestClientContextCustomizerIntegrationTests.java b/integration-test/spring-boot-test-integration-tests/src/test/java/org/springframework/boot/test/web/reactive/client/WebTestClientContextCustomizerIntegrationTests.java
similarity index 97%
rename from module/spring-boot-web-server-test/src/test/java/org/springframework/boot/web/server/test/client/reactive/WebTestClientContextCustomizerIntegrationTests.java
rename to integration-test/spring-boot-test-integration-tests/src/test/java/org/springframework/boot/test/web/reactive/client/WebTestClientContextCustomizerIntegrationTests.java
index c6ca610ca54..08ad57f5ce6 100644
--- a/module/spring-boot-web-server-test/src/test/java/org/springframework/boot/web/server/test/client/reactive/WebTestClientContextCustomizerIntegrationTests.java
+++ b/integration-test/spring-boot-test-integration-tests/src/test/java/org/springframework/boot/test/web/reactive/client/WebTestClientContextCustomizerIntegrationTests.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package org.springframework.boot.web.server.test.client.reactive;
+package org.springframework.boot.test.web.reactive.client;
import org.junit.jupiter.api.Test;
import reactor.core.publisher.Mono;
diff --git a/module/spring-boot-web-server-test/src/test/java/org/springframework/boot/web/server/test/client/reactive/WebTestClientContextCustomizerTcfCacheContextPausingTests.java b/integration-test/spring-boot-test-integration-tests/src/test/java/org/springframework/boot/test/web/reactive/client/WebTestClientContextCustomizerTcfCacheContextPausingTests.java
similarity index 98%
rename from module/spring-boot-web-server-test/src/test/java/org/springframework/boot/web/server/test/client/reactive/WebTestClientContextCustomizerTcfCacheContextPausingTests.java
rename to integration-test/spring-boot-test-integration-tests/src/test/java/org/springframework/boot/test/web/reactive/client/WebTestClientContextCustomizerTcfCacheContextPausingTests.java
index adbdad6854b..99267d0cf9e 100644
--- a/module/spring-boot-web-server-test/src/test/java/org/springframework/boot/web/server/test/client/reactive/WebTestClientContextCustomizerTcfCacheContextPausingTests.java
+++ b/integration-test/spring-boot-test-integration-tests/src/test/java/org/springframework/boot/test/web/reactive/client/WebTestClientContextCustomizerTcfCacheContextPausingTests.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package org.springframework.boot.web.server.test.client.reactive;
+package org.springframework.boot.test.web.reactive.client;
import java.util.Collections;
import java.util.Map;
diff --git a/module/spring-boot-web-server-test/src/test/java/org/springframework/boot/web/server/test/client/reactive/WebTestClientContextCustomizerTests.java b/integration-test/spring-boot-test-integration-tests/src/test/java/org/springframework/boot/test/web/reactive/client/WebTestClientContextCustomizerTests.java
similarity index 94%
rename from module/spring-boot-web-server-test/src/test/java/org/springframework/boot/web/server/test/client/reactive/WebTestClientContextCustomizerTests.java
rename to integration-test/spring-boot-test-integration-tests/src/test/java/org/springframework/boot/test/web/reactive/client/WebTestClientContextCustomizerTests.java
index e0280a9e9c0..71603526cce 100644
--- a/module/spring-boot-web-server-test/src/test/java/org/springframework/boot/web/server/test/client/reactive/WebTestClientContextCustomizerTests.java
+++ b/integration-test/spring-boot-test-integration-tests/src/test/java/org/springframework/boot/test/web/reactive/client/WebTestClientContextCustomizerTests.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package org.springframework.boot.web.server.test.client.reactive;
+package org.springframework.boot.test.web.reactive.client;
import org.junit.jupiter.api.Test;
@@ -23,7 +23,7 @@ import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
-import org.springframework.boot.web.server.test.client.reactive.WebTestClientContextCustomizer.WebTestClientRegistrar;
+import org.springframework.boot.test.web.reactive.client.WebTestClientContextCustomizer.WebTestClientRegistrar;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.test.context.MergedContextConfiguration;
diff --git a/module/spring-boot-web-server-test/src/test/java/org/springframework/boot/web/server/test/client/reactive/WebTestClientContextCustomizerWithCustomBasePathTests.java b/integration-test/spring-boot-test-integration-tests/src/test/java/org/springframework/boot/test/web/reactive/client/WebTestClientContextCustomizerWithCustomBasePathTests.java
similarity index 97%
rename from module/spring-boot-web-server-test/src/test/java/org/springframework/boot/web/server/test/client/reactive/WebTestClientContextCustomizerWithCustomBasePathTests.java
rename to integration-test/spring-boot-test-integration-tests/src/test/java/org/springframework/boot/test/web/reactive/client/WebTestClientContextCustomizerWithCustomBasePathTests.java
index f039b59b626..48e253e5b9a 100644
--- a/module/spring-boot-web-server-test/src/test/java/org/springframework/boot/web/server/test/client/reactive/WebTestClientContextCustomizerWithCustomBasePathTests.java
+++ b/integration-test/spring-boot-test-integration-tests/src/test/java/org/springframework/boot/test/web/reactive/client/WebTestClientContextCustomizerWithCustomBasePathTests.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package org.springframework.boot.web.server.test.client.reactive;
+package org.springframework.boot.test.web.reactive.client;
import java.util.Collections;
import java.util.Map;
diff --git a/module/spring-boot-web-server-test/src/test/java/org/springframework/boot/web/server/test/client/reactive/WebTestClientContextCustomizerWithCustomContextPathTests.java b/integration-test/spring-boot-test-integration-tests/src/test/java/org/springframework/boot/test/web/reactive/client/WebTestClientContextCustomizerWithCustomContextPathTests.java
similarity index 97%
rename from module/spring-boot-web-server-test/src/test/java/org/springframework/boot/web/server/test/client/reactive/WebTestClientContextCustomizerWithCustomContextPathTests.java
rename to integration-test/spring-boot-test-integration-tests/src/test/java/org/springframework/boot/test/web/reactive/client/WebTestClientContextCustomizerWithCustomContextPathTests.java
index 04c278d79b4..33b1750ab04 100644
--- a/module/spring-boot-web-server-test/src/test/java/org/springframework/boot/web/server/test/client/reactive/WebTestClientContextCustomizerWithCustomContextPathTests.java
+++ b/integration-test/spring-boot-test-integration-tests/src/test/java/org/springframework/boot/test/web/reactive/client/WebTestClientContextCustomizerWithCustomContextPathTests.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package org.springframework.boot.web.server.test.client.reactive;
+package org.springframework.boot.test.web.reactive.client;
import org.junit.jupiter.api.Test;
diff --git a/module/spring-boot-web-server-test/src/test/java/org/springframework/boot/web/server/test/client/reactive/WebTestClientContextCustomizerWithOverrideIntegrationTests.java b/integration-test/spring-boot-test-integration-tests/src/test/java/org/springframework/boot/test/web/reactive/client/WebTestClientContextCustomizerWithOverrideIntegrationTests.java
similarity index 97%
rename from module/spring-boot-web-server-test/src/test/java/org/springframework/boot/web/server/test/client/reactive/WebTestClientContextCustomizerWithOverrideIntegrationTests.java
rename to integration-test/spring-boot-test-integration-tests/src/test/java/org/springframework/boot/test/web/reactive/client/WebTestClientContextCustomizerWithOverrideIntegrationTests.java
index a5e92eb24d3..175ea9ed8e1 100644
--- a/module/spring-boot-web-server-test/src/test/java/org/springframework/boot/web/server/test/client/reactive/WebTestClientContextCustomizerWithOverrideIntegrationTests.java
+++ b/integration-test/spring-boot-test-integration-tests/src/test/java/org/springframework/boot/test/web/reactive/client/WebTestClientContextCustomizerWithOverrideIntegrationTests.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package org.springframework.boot.web.server.test.client.reactive;
+package org.springframework.boot.test.web.reactive.client;
import org.junit.jupiter.api.Test;
import reactor.core.publisher.Mono;
diff --git a/module/spring-boot-web-server-test/src/test/java/org/springframework/boot/web/server/test/client/reactive/WebTestClientContextCustomizerWithoutWebfluxIntegrationTests.java b/integration-test/spring-boot-test-integration-tests/src/test/java/org/springframework/boot/test/web/reactive/client/WebTestClientContextCustomizerWithoutWebfluxIntegrationTests.java
similarity index 96%
rename from module/spring-boot-web-server-test/src/test/java/org/springframework/boot/web/server/test/client/reactive/WebTestClientContextCustomizerWithoutWebfluxIntegrationTests.java
rename to integration-test/spring-boot-test-integration-tests/src/test/java/org/springframework/boot/test/web/reactive/client/WebTestClientContextCustomizerWithoutWebfluxIntegrationTests.java
index bd81bbc26cb..e2af56eead6 100644
--- a/module/spring-boot-web-server-test/src/test/java/org/springframework/boot/web/server/test/client/reactive/WebTestClientContextCustomizerWithoutWebfluxIntegrationTests.java
+++ b/integration-test/spring-boot-test-integration-tests/src/test/java/org/springframework/boot/test/web/reactive/client/WebTestClientContextCustomizerWithoutWebfluxIntegrationTests.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package org.springframework.boot.web.server.test.client.reactive;
+package org.springframework.boot.test.web.reactive.client;
import java.util.Collections;
diff --git a/module/spring-boot-http-codec/build.gradle b/module/spring-boot-http-codec/build.gradle
index 0d00da56d8f..ae0f6d0b243 100644
--- a/module/spring-boot-http-codec/build.gradle
+++ b/module/spring-boot-http-codec/build.gradle
@@ -29,6 +29,7 @@ dependencies {
api("org.springframework:spring-web")
optional(project(":core:spring-boot-autoconfigure"))
+ optional(project(":core:spring-boot-test"))
optional(project(":module:spring-boot-jackson"))
optional("org.springframework:spring-webflux")
diff --git a/module/spring-boot-http-codec/src/main/java/org/springframework/boot/http/codec/CodecWebTestClientBuilderCustomizer.java b/module/spring-boot-http-codec/src/main/java/org/springframework/boot/http/codec/CodecWebTestClientBuilderCustomizer.java
new file mode 100644
index 00000000000..1d946ef79de
--- /dev/null
+++ b/module/spring-boot-http-codec/src/main/java/org/springframework/boot/http/codec/CodecWebTestClientBuilderCustomizer.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2012-present 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.boot.http.codec;
+
+import java.util.Collection;
+import java.util.function.Consumer;
+
+import org.springframework.boot.test.web.reactive.client.WebTestClientBuilderCustomizer;
+import org.springframework.context.ApplicationContext;
+import org.springframework.http.codec.ClientCodecConfigurer;
+import org.springframework.test.web.reactive.server.WebTestClient.Builder;
+import org.springframework.util.CollectionUtils;
+import org.springframework.web.reactive.function.client.ExchangeStrategies;
+
+/**
+ * {@link WebTestClientBuilderCustomizer} to apply {@link CodecCustomizer} beans.
+ *
+ * @author Phillip Webb
+ */
+class CodecWebTestClientBuilderCustomizer implements WebTestClientBuilderCustomizer {
+
+ private final ApplicationContext context;
+
+ CodecWebTestClientBuilderCustomizer(ApplicationContext context) {
+ this.context = context;
+ }
+
+ @Override
+ public void customize(Builder builder) {
+ Collection customizers = this.context.getBeansOfType(CodecCustomizer.class).values();
+ if (!CollectionUtils.isEmpty(customizers)) {
+ ExchangeStrategies strategies = ExchangeStrategies.builder().codecs(apply(customizers)).build();
+ builder.exchangeStrategies(strategies);
+ }
+ }
+
+ private Consumer apply(Collection customizers) {
+ return (codecs) -> customizers.forEach((customizer) -> customizer.customize(codecs));
+ }
+
+}
diff --git a/module/spring-boot-http-codec/src/main/resources/META-INF/spring.factories b/module/spring-boot-http-codec/src/main/resources/META-INF/spring.factories
new file mode 100644
index 00000000000..48faac4bcbd
--- /dev/null
+++ b/module/spring-boot-http-codec/src/main/resources/META-INF/spring.factories
@@ -0,0 +1,3 @@
+# WebTestClient Builder Customizers
+org.springframework.boot.test.web.reactive.server.WebTestClientBuilderCustomizer=\
+org.springframework.boot.http.codec.CodecWebTestClientBuilderCustomizer
diff --git a/module/spring-boot-restdocs/src/main/java/org/springframework/boot/restdocs/test/autoconfigure/RestDocsWebTestClientBuilderCustomizer.java b/module/spring-boot-restdocs/src/main/java/org/springframework/boot/restdocs/test/autoconfigure/RestDocsWebTestClientBuilderCustomizer.java
index b8338e9e754..e09e5263ff8 100644
--- a/module/spring-boot-restdocs/src/main/java/org/springframework/boot/restdocs/test/autoconfigure/RestDocsWebTestClientBuilderCustomizer.java
+++ b/module/spring-boot-restdocs/src/main/java/org/springframework/boot/restdocs/test/autoconfigure/RestDocsWebTestClientBuilderCustomizer.java
@@ -18,7 +18,7 @@ package org.springframework.boot.restdocs.test.autoconfigure;
import org.jspecify.annotations.Nullable;
-import org.springframework.boot.web.server.test.client.reactive.WebTestClientBuilderCustomizer;
+import org.springframework.boot.test.web.reactive.client.WebTestClientBuilderCustomizer;
import org.springframework.restdocs.webtestclient.WebTestClientRestDocumentationConfigurer;
import org.springframework.test.web.reactive.server.WebTestClient;
import org.springframework.util.StringUtils;
diff --git a/module/spring-boot-web-server-test/src/main/resources/META-INF/spring.factories b/module/spring-boot-web-server-test/src/main/resources/META-INF/spring.factories
index 7b66b762df7..aa63dda60b1 100644
--- a/module/spring-boot-web-server-test/src/main/resources/META-INF/spring.factories
+++ b/module/spring-boot-web-server-test/src/main/resources/META-INF/spring.factories
@@ -6,5 +6,4 @@ org.springframework.boot.web.server.test.SpringBootTestRandomPortEnvironmentPost
org.springframework.test.context.ContextCustomizerFactory=\
org.springframework.boot.web.server.test.client.RestTestClientContextCustomizerFactory,\
org.springframework.boot.web.server.test.client.TestRestTemplateContextCustomizerFactory,\
-org.springframework.boot.web.server.test.client.reactive.WebTestClientContextCustomizerFactory,\
org.springframework.boot.web.server.test.reactor.netty.DisableReactorResourceFactoryGlobalResourcesContextCustomizerFactory
diff --git a/module/spring-boot-web-server/build.gradle b/module/spring-boot-web-server/build.gradle
index b684dfced6f..7e933e552dd 100644
--- a/module/spring-boot-web-server/build.gradle
+++ b/module/spring-boot-web-server/build.gradle
@@ -29,6 +29,7 @@ dependencies {
api("org.springframework:spring-web")
optional(project(":core:spring-boot-autoconfigure"))
+ optional(project(":core:spring-boot-test"))
optional("io.projectreactor:reactor-core")
optional("jakarta.servlet:jakarta.servlet-api")
optional("org.springframework:spring-test")
diff --git a/module/spring-boot-webflux-test/src/main/java/org/springframework/boot/webflux/test/autoconfigure/SpringBootWebTestClientBuilderCustomizer.java b/module/spring-boot-webflux-test/src/main/java/org/springframework/boot/webflux/test/autoconfigure/SpringBootWebTestClientBuilderCustomizer.java
index c9a7e545c84..0b211c2d041 100644
--- a/module/spring-boot-webflux-test/src/main/java/org/springframework/boot/webflux/test/autoconfigure/SpringBootWebTestClientBuilderCustomizer.java
+++ b/module/spring-boot-webflux-test/src/main/java/org/springframework/boot/webflux/test/autoconfigure/SpringBootWebTestClientBuilderCustomizer.java
@@ -23,7 +23,7 @@ import java.util.function.Consumer;
import org.jspecify.annotations.Nullable;
import org.springframework.boot.http.codec.CodecCustomizer;
-import org.springframework.boot.web.server.test.client.reactive.WebTestClientBuilderCustomizer;
+import org.springframework.boot.test.web.reactive.client.WebTestClientBuilderCustomizer;
import org.springframework.http.codec.ClientCodecConfigurer;
import org.springframework.test.web.reactive.server.WebTestClient;
import org.springframework.test.web.reactive.server.WebTestClient.Builder;
diff --git a/module/spring-boot-webflux-test/src/main/java/org/springframework/boot/webflux/test/autoconfigure/WebTestClientAutoConfiguration.java b/module/spring-boot-webflux-test/src/main/java/org/springframework/boot/webflux/test/autoconfigure/WebTestClientAutoConfiguration.java
index 4125d53e52b..d27464c4638 100644
--- a/module/spring-boot-webflux-test/src/main/java/org/springframework/boot/webflux/test/autoconfigure/WebTestClientAutoConfiguration.java
+++ b/module/spring-boot-webflux-test/src/main/java/org/springframework/boot/webflux/test/autoconfigure/WebTestClientAutoConfiguration.java
@@ -26,7 +26,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.http.codec.CodecCustomizer;
-import org.springframework.boot.web.server.test.client.reactive.WebTestClientBuilderCustomizer;
+import org.springframework.boot.test.web.reactive.client.WebTestClientBuilderCustomizer;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.test.web.reactive.server.MockServerConfigurer;
diff --git a/module/spring-boot-webmvc-test/src/main/java/org/springframework/boot/webmvc/test/autoconfigure/MockMvcAutoConfiguration.java b/module/spring-boot-webmvc-test/src/main/java/org/springframework/boot/webmvc/test/autoconfigure/MockMvcAutoConfiguration.java
index d3cef4a06d1..b70016d4764 100644
--- a/module/spring-boot-webmvc-test/src/main/java/org/springframework/boot/webmvc/test/autoconfigure/MockMvcAutoConfiguration.java
+++ b/module/spring-boot-webmvc-test/src/main/java/org/springframework/boot/webmvc/test/autoconfigure/MockMvcAutoConfiguration.java
@@ -24,9 +24,9 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.boot.test.web.reactive.client.WebTestClientBuilderCustomizer;
+import org.springframework.boot.test.web.servlet.client.RestTestClientBuilderCustomizer;
import org.springframework.boot.web.server.autoconfigure.ServerProperties;
-import org.springframework.boot.web.server.test.client.RestTestClientBuilderCustomizer;
-import org.springframework.boot.web.server.test.client.reactive.WebTestClientBuilderCustomizer;
import org.springframework.boot.webmvc.autoconfigure.DispatcherServletPath;
import org.springframework.boot.webmvc.autoconfigure.WebMvcAutoConfiguration;
import org.springframework.boot.webmvc.autoconfigure.WebMvcProperties;
diff --git a/module/spring-boot-webmvc-test/src/test/java/org/springframework/boot/webmvc/test/autoconfigure/MockMvcAutoConfigurationTests.java b/module/spring-boot-webmvc-test/src/test/java/org/springframework/boot/webmvc/test/autoconfigure/MockMvcAutoConfigurationTests.java
index 85e4f80c112..22671c3c576 100644
--- a/module/spring-boot-webmvc-test/src/test/java/org/springframework/boot/webmvc/test/autoconfigure/MockMvcAutoConfigurationTests.java
+++ b/module/spring-boot-webmvc-test/src/test/java/org/springframework/boot/webmvc/test/autoconfigure/MockMvcAutoConfigurationTests.java
@@ -21,8 +21,8 @@ import org.junit.jupiter.api.Test;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.test.context.FilteredClassLoader;
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
+import org.springframework.boot.test.web.reactive.client.WebTestClientBuilderCustomizer;
import org.springframework.boot.web.server.test.client.RestTestClientBuilderCustomizer;
-import org.springframework.boot.web.server.test.client.reactive.WebTestClientBuilderCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.test.web.reactive.server.WebTestClient;
diff --git a/settings.gradle b/settings.gradle
index 97f524b86fb..8a47cc323cd 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -405,6 +405,7 @@ include ":integration-test:spring-boot-launch-script-integration-tests"
include ":integration-test:spring-boot-loader-integration-tests"
include ":integration-test:spring-boot-server-integration-tests"
include ":integration-test:spring-boot-sni-integration-tests"
+include ":integration-test:spring-boot-test-integration-tests"
include ":system-test:spring-boot-deployment-system-tests"
include ":system-test:spring-boot-image-system-tests"