diff --git a/spring-test/src/main/java/org/springframework/test/web/reactive/server/DefaultWebTestClientBuilder.java b/spring-test/src/main/java/org/springframework/test/web/reactive/server/DefaultWebTestClientBuilder.java
index f3c9e3650a..136cc93274 100644
--- a/spring-test/src/main/java/org/springframework/test/web/reactive/server/DefaultWebTestClientBuilder.java
+++ b/spring-test/src/main/java/org/springframework/test/web/reactive/server/DefaultWebTestClientBuilder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2022 the original author or authors.
+ * Copyright 2002-2023 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.
@@ -80,7 +80,7 @@ class DefaultWebTestClientBuilder implements WebTestClient.Builder {
private final WebHttpHandlerBuilder httpHandlerBuilder;
@Nullable
- private final ClientHttpConnector connector;
+ private ClientHttpConnector connector;
@Nullable
private String baseUrl;
@@ -277,6 +277,12 @@ class DefaultWebTestClientBuilder implements WebTestClient.Builder {
return this;
}
+ @Override
+ public WebTestClient.Builder clientConnector(ClientHttpConnector connector) {
+ this.connector = connector;
+ return this;
+ }
+
@Override
public WebTestClient build() {
ClientHttpConnector connectorToUse = this.connector;
diff --git a/spring-test/src/main/java/org/springframework/test/web/reactive/server/WebTestClient.java b/spring-test/src/main/java/org/springframework/test/web/reactive/server/WebTestClient.java
index 5b264b1c9d..622c6f9d79 100644
--- a/spring-test/src/main/java/org/springframework/test/web/reactive/server/WebTestClient.java
+++ b/spring-test/src/main/java/org/springframework/test/web/reactive/server/WebTestClient.java
@@ -512,6 +512,18 @@ public interface WebTestClient {
*/
Builder responseTimeout(Duration timeout);
+ /**
+ * Set the {@link ClientHttpConnector} to use.
+ *
By default, this is initialized and set internally. However, the
+ * connector may also be prepared externally and passed via
+ * {@link WebTestClient#bindToServer(ClientHttpConnector)} such as for
+ * {@code MockMvcWebTestClient} tests, and in that case you can use this
+ * from {@link #mutateWith(WebTestClientConfigurer)} to replace it.
+ * @param connector the connector to use
+ * @since 6.1
+ */
+ Builder clientConnector(ClientHttpConnector connector);
+
/**
* Apply the given configurer to this builder instance.
*
This can be useful for applying pre-packaged customizations.
diff --git a/spring-test/src/main/java/org/springframework/test/web/servlet/client/MockMvcHttpConnector.java b/spring-test/src/main/java/org/springframework/test/web/servlet/client/MockMvcHttpConnector.java
index b7fa5dbd35..36a49b58c2 100644
--- a/spring-test/src/main/java/org/springframework/test/web/servlet/client/MockMvcHttpConnector.java
+++ b/spring-test/src/main/java/org/springframework/test/web/servlet/client/MockMvcHttpConnector.java
@@ -19,6 +19,7 @@ package org.springframework.test.web.servlet.client;
import java.io.StringWriter;
import java.net.URI;
import java.time.Duration;
+import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;
@@ -56,6 +57,7 @@ import org.springframework.test.web.servlet.RequestBuilder;
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
import org.springframework.test.web.servlet.request.MockMultipartHttpServletRequestBuilder;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
+import org.springframework.test.web.servlet.request.RequestPostProcessor;
import org.springframework.test.web.servlet.result.MockMvcResultHandlers;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
@@ -82,9 +84,16 @@ public class MockMvcHttpConnector implements ClientHttpConnector {
private final MockMvc mockMvc;
+ private final List requestPostProcessors;
+
public MockMvcHttpConnector(MockMvc mockMvc) {
+ this(mockMvc, Collections.emptyList());
+ }
+
+ private MockMvcHttpConnector(MockMvc mockMvc, List requestPostProcessors) {
this.mockMvc = mockMvc;
+ this.requestPostProcessors = new ArrayList<>(requestPostProcessors);
}
@@ -135,6 +144,8 @@ public class MockMvcHttpConnector implements ClientHttpConnector {
}
}
+ this.requestPostProcessors.forEach(requestBuilder::with);
+
return requestBuilder;
}
@@ -207,6 +218,15 @@ public class MockMvcHttpConnector implements ClientHttpConnector {
return clientResponse;
}
+ /**
+ * Create a new instance that applies the given {@link RequestPostProcessor}s
+ * to performed requests.
+ * @since 6.1
+ */
+ public MockMvcHttpConnector with(List postProcessors) {
+ return new MockMvcHttpConnector(this.mockMvc, postProcessors);
+ }
+
private static class MockMvcServerClientHttpResponse
extends MockClientHttpResponse implements MockServerClientHttpResponse {
diff --git a/spring-test/src/test/java/org/springframework/test/web/servlet/samples/client/standalone/FrameworkExtensionTests.java b/spring-test/src/test/java/org/springframework/test/web/servlet/samples/client/standalone/FrameworkExtensionTests.java
index ad9efb79ca..bfbc8d6a10 100644
--- a/spring-test/src/test/java/org/springframework/test/web/servlet/samples/client/standalone/FrameworkExtensionTests.java
+++ b/spring-test/src/test/java/org/springframework/test/web/servlet/samples/client/standalone/FrameworkExtensionTests.java
@@ -17,11 +17,17 @@
package org.springframework.test.web.servlet.samples.client.standalone;
import java.security.Principal;
+import java.util.List;
import org.junit.jupiter.api.Test;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.client.reactive.ClientHttpConnector;
+import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.stereotype.Controller;
import org.springframework.test.web.reactive.server.WebTestClient;
+import org.springframework.test.web.reactive.server.WebTestClientConfigurer;
+import org.springframework.test.web.servlet.client.MockMvcHttpConnector;
import org.springframework.test.web.servlet.client.MockMvcWebTestClient;
import org.springframework.test.web.servlet.request.RequestPostProcessor;
import org.springframework.test.web.servlet.setup.ConfigurableMockMvcBuilder;
@@ -30,6 +36,7 @@ import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.context.WebApplicationContext;
+import org.springframework.web.server.adapter.WebHttpHandlerBuilder;
import static org.mockito.Mockito.mock;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@@ -50,16 +57,16 @@ public class FrameworkExtensionTests {
@Test
public void fooHeader() {
- this.client.get().uri("/")
- .header("Foo", "a=b")
+ this.client.mutateWith(headers().foo("a=b"))
+ .get().uri("/")
.exchange()
.expectBody(String.class).isEqualTo("Foo");
}
@Test
public void barHeader() {
- this.client.get().uri("/")
- .header("Bar", "a=b")
+ this.client.mutateWith(headers().bar("a=b"))
+ .get().uri("/")
.exchange()
.expectBody(String.class).isEqualTo("Bar");
}
@@ -68,6 +75,68 @@ public class FrameworkExtensionTests {
return new TestMockMvcConfigurer();
}
+ private static TestWebTestClientConfigurer headers() {
+ return new TestWebTestClientConfigurer();
+ }
+
+
+ /**
+ * Test WebTestClientConfigurer that re-creates the MockMvcHttpConnector
+ * with a {@code TestRequestPostProcessor}.
+ */
+ private static class TestWebTestClientConfigurer implements WebTestClientConfigurer {
+
+ private final TestRequestPostProcessor requestPostProcessor = new TestRequestPostProcessor();
+
+ public TestWebTestClientConfigurer foo(String value) {
+ this.requestPostProcessor.foo(value);
+ return this;
+ }
+
+ public TestWebTestClientConfigurer bar(String value) {
+ this.requestPostProcessor.bar(value);
+ return this;
+ }
+
+ @Override
+ public void afterConfigurerAdded(
+ WebTestClient.Builder builder, WebHttpHandlerBuilder httpHandlerBuilder,
+ ClientHttpConnector connector) {
+
+ if (connector instanceof MockMvcHttpConnector mockMvcConnector) {
+ builder.clientConnector(mockMvcConnector.with(List.of(this.requestPostProcessor)));
+ }
+ }
+ }
+
+
+ /**
+ * Test {@code RequestPostProcessor} for custom headers.
+ */
+ private static class TestRequestPostProcessor implements RequestPostProcessor {
+
+ private final HttpHeaders headers = new HttpHeaders();
+
+
+ public TestRequestPostProcessor foo(String value) {
+ this.headers.add("Foo", value);
+ return this;
+ }
+
+ public TestRequestPostProcessor bar(String value) {
+ this.headers.add("Bar", value);
+ return this;
+ }
+
+ @Override
+ public MockHttpServletRequest postProcessRequest(MockHttpServletRequest request) {
+ for (String headerName : this.headers.keySet()) {
+ request.addHeader(headerName, this.headers.get(headerName));
+ }
+ return request;
+ }
+ }
+
/**
* Test {@code MockMvcConfigurer}.
@@ -80,8 +149,9 @@ public class FrameworkExtensionTests {
}
@Override
- public RequestPostProcessor beforeMockMvcCreated(ConfigurableMockMvcBuilder> builder,
- WebApplicationContext context) {
+ public RequestPostProcessor beforeMockMvcCreated(
+ ConfigurableMockMvcBuilder> builder, WebApplicationContext context) {
+
return request -> {
request.setUserPrincipal(mock());
return request;
diff --git a/spring-test/src/test/java/org/springframework/test/web/servlet/samples/standalone/FrameworkExtensionTests.java b/spring-test/src/test/java/org/springframework/test/web/servlet/samples/standalone/FrameworkExtensionTests.java
index 4373e133b4..0af7bbccce 100644
--- a/spring-test/src/test/java/org/springframework/test/web/servlet/samples/standalone/FrameworkExtensionTests.java
+++ b/spring-test/src/test/java/org/springframework/test/web/servlet/samples/standalone/FrameworkExtensionTests.java
@@ -18,7 +18,6 @@ package org.springframework.test.web.servlet.samples.standalone;
import java.security.Principal;
-import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.http.HttpHeaders;
@@ -53,14 +52,9 @@ import static org.springframework.test.web.servlet.setup.MockMvcBuilders.standal
*/
public class FrameworkExtensionTests {
- private MockMvc mockMvc;
+ private final MockMvc mockMvc = standaloneSetup(new SampleController()).apply(defaultSetup()).build();
- @BeforeEach
- public void setup() {
- this.mockMvc = standaloneSetup(new SampleController()).apply(defaultSetup()).build();
- }
-
@Test
public void fooHeader() throws Exception {
this.mockMvc.perform(get("/").with(headers().foo("a=b"))).andExpect(content().string("Foo"));
@@ -81,7 +75,7 @@ public class FrameworkExtensionTests {
/**
- * Test {@code RequestPostProcessor}.
+ * Test {@code RequestPostProcessor} for custom headers.
*/
private static class TestRequestPostProcessor implements RequestPostProcessor {
@@ -119,8 +113,9 @@ public class FrameworkExtensionTests {
}
@Override
- public RequestPostProcessor beforeMockMvcCreated(ConfigurableMockMvcBuilder> builder,
- WebApplicationContext context) {
+ public RequestPostProcessor beforeMockMvcCreated(
+ ConfigurableMockMvcBuilder> builder, WebApplicationContext context) {
+
return request -> {
request.setUserPrincipal(mock());
return request;