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 210146bc83f..4d9c30fbc1b 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 @@ -155,7 +155,7 @@ public interface WebTestClient { /** - * Return a builder to mutate properties of this web test client. + * Return a builder to mutate properties of this test client. */ Builder mutate(); @@ -171,8 +171,6 @@ public interface WebTestClient { WebTestClient mutateWith(WebTestClientConfigurer configurer); - // Static factory methods - /** * Use this server setup to test one {@code @Controller} at a time. * This option loads the default configuration of diff --git a/spring-test/src/main/java/org/springframework/test/web/servlet/client/DefaultMockServerBuilder.java b/spring-test/src/main/java/org/springframework/test/web/servlet/client/DefaultMockServerBuilder.java deleted file mode 100644 index 9cfdf87f9fa..00000000000 --- a/spring-test/src/main/java/org/springframework/test/web/servlet/client/DefaultMockServerBuilder.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2002-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.test.web.servlet.client; - -import java.util.function.Consumer; - -import org.springframework.test.web.servlet.MockMvcBuilder; - -/** - * Default implementation of {@link RestTestClient.MockServerBuilder}. - * @author Rob Worsnop - * @param the type of the {@link MockMvcBuilder} to use for building the mock server - */ -class DefaultMockServerBuilder - extends DefaultRestTestClientBuilder> - implements RestTestClient.MockServerBuilder { - - private final M builder; - - public DefaultMockServerBuilder(M builder) { - this.builder = builder; - } - - @Override - public RestTestClient.MockServerBuilder configureServer(Consumer consumer) { - consumer.accept(this.builder); - return this; - } - - @Override - public RestTestClient build() { - this.restClientBuilder.requestFactory(new MockMvcClientHttpRequestFactory(this.builder.build())); - return super.build(); - } -} diff --git a/spring-test/src/main/java/org/springframework/test/web/servlet/client/DefaultRestTestClientBuilder.java b/spring-test/src/main/java/org/springframework/test/web/servlet/client/DefaultRestTestClientBuilder.java index 4e4b722e30a..48c1d255b07 100644 --- a/spring-test/src/main/java/org/springframework/test/web/servlet/client/DefaultRestTestClientBuilder.java +++ b/spring-test/src/main/java/org/springframework/test/web/servlet/client/DefaultRestTestClientBuilder.java @@ -18,9 +18,20 @@ package org.springframework.test.web.servlet.client; import java.util.function.Consumer; +import org.jspecify.annotations.Nullable; + import org.springframework.http.HttpHeaders; +import org.springframework.http.client.ClientHttpRequestFactory; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.MockMvcBuilder; +import org.springframework.test.web.servlet.setup.DefaultMockMvcBuilder; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.test.web.servlet.setup.RouterFunctionMockMvcBuilder; +import org.springframework.test.web.servlet.setup.StandaloneMockMvcBuilder; import org.springframework.util.MultiValueMap; import org.springframework.web.client.RestClient; +import org.springframework.web.context.WebApplicationContext; +import org.springframework.web.servlet.function.RouterFunction; import org.springframework.web.util.UriBuilderFactory; /** @@ -33,7 +44,7 @@ import org.springframework.web.util.UriBuilderFactory; */ class DefaultRestTestClientBuilder> implements RestTestClient.Builder { - protected final RestClient.Builder restClientBuilder; + private final RestClient.Builder restClientBuilder; DefaultRestTestClientBuilder() { @@ -46,49 +57,110 @@ class DefaultRestTestClientBuilder> implemen @Override - public RestTestClient.Builder baseUrl(String baseUrl) { + public T baseUrl(String baseUrl) { this.restClientBuilder.baseUrl(baseUrl); - return this; + return self(); } @Override - public RestTestClient.Builder uriBuilderFactory(UriBuilderFactory uriFactory) { + public T uriBuilderFactory(UriBuilderFactory uriFactory) { this.restClientBuilder.uriBuilderFactory(uriFactory); - return this; + return self(); } @Override - public RestTestClient.Builder defaultHeader(String headerName, String... headerValues) { + public T defaultHeader(String headerName, String... headerValues) { this.restClientBuilder.defaultHeader(headerName, headerValues); - return this; + return self(); } @Override - public RestTestClient.Builder defaultHeaders(Consumer headersConsumer) { + public T defaultHeaders(Consumer headersConsumer) { this.restClientBuilder.defaultHeaders(headersConsumer); - return this; + return self(); } @Override - public RestTestClient.Builder defaultCookie(String cookieName, String... cookieValues) { + public T defaultCookie(String cookieName, String... cookieValues) { this.restClientBuilder.defaultCookie(cookieName, cookieValues); - return this; + return self(); } @Override - public RestTestClient.Builder defaultCookies(Consumer> cookiesConsumer) { + public T defaultCookies(Consumer> cookiesConsumer) { this.restClientBuilder.defaultCookies(cookiesConsumer); - return this; + return self(); } @Override - public RestTestClient.Builder apply(Consumer> builderConsumer) { + public T apply(Consumer> builderConsumer) { builderConsumer.accept(this); - return this; + return self(); + } + + @SuppressWarnings("unchecked") + protected T self() { + return (T) this; + } + + protected void setClientHttpRequestFactory(ClientHttpRequestFactory requestFactory) { + this.restClientBuilder.requestFactory(requestFactory); } @Override public RestTestClient build() { return new DefaultRestTestClient(this.restClientBuilder); } + + + static class AbstractMockMvcSetupBuilder, M extends MockMvcBuilder> + extends DefaultRestTestClientBuilder implements RestTestClient.MockMvcSetupBuilder { + + private final M mockMvcBuilder; + + public AbstractMockMvcSetupBuilder(M mockMvcBuilder) { + this.mockMvcBuilder = mockMvcBuilder; + } + + public T configureServer(Consumer consumer) { + consumer.accept(this.mockMvcBuilder); + return self(); + } + + @Override + public RestTestClient build() { + MockMvc mockMvc = this.mockMvcBuilder.build(); + setClientHttpRequestFactory(new MockMvcClientHttpRequestFactory(mockMvc)); + return super.build(); + } + } + + + static class DefaultStandaloneSetupBuilder extends AbstractMockMvcSetupBuilder + implements RestTestClient.StandaloneSetupBuilder { + + DefaultStandaloneSetupBuilder(Object... controllers) { + super(MockMvcBuilders.standaloneSetup(controllers)); + } + } + + + static class DefaultRouterFunctionSetupBuilder extends AbstractMockMvcSetupBuilder + implements RestTestClient.RouterFunctionSetupBuilder { + + DefaultRouterFunctionSetupBuilder(RouterFunction... routerFunctions) { + super(MockMvcBuilders.routerFunctions(routerFunctions)); + } + + } + + + static class DefaultWebAppContextSetupBuilder extends AbstractMockMvcSetupBuilder + implements RestTestClient.WebAppContextSetupBuilder { + + DefaultWebAppContextSetupBuilder(WebApplicationContext context) { + super(MockMvcBuilders.webAppContextSetup(context)); + } + } + } diff --git a/spring-test/src/main/java/org/springframework/test/web/servlet/client/RestTestClient.java b/spring-test/src/main/java/org/springframework/test/web/servlet/client/RestTestClient.java index 4dcd74026f0..32bbed7535a 100644 --- a/spring-test/src/main/java/org/springframework/test/web/servlet/client/RestTestClient.java +++ b/spring-test/src/main/java/org/springframework/test/web/servlet/client/RestTestClient.java @@ -37,7 +37,6 @@ import org.springframework.test.json.JsonComparison; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.MockMvcBuilder; import org.springframework.test.web.servlet.setup.DefaultMockMvcBuilder; -import org.springframework.test.web.servlet.setup.MockMvcBuilders; import org.springframework.test.web.servlet.setup.RouterFunctionMockMvcBuilder; import org.springframework.test.web.servlet.setup.StandaloneMockMvcBuilder; import org.springframework.util.MultiValueMap; @@ -51,6 +50,8 @@ import org.springframework.web.util.UriBuilderFactory; * Client for testing web servers. * * @author Rob Worsnop + * @author Rossen Stoyanchev + * @since 7.0 */ public interface RestTestClient { @@ -126,9 +127,8 @@ public interface RestTestClient { * {@link org.springframework.test.web.servlet.setup.MockMvcBuilders#standaloneSetup(Object...)} * to initialize {@link MockMvc}. */ - static MockServerBuilder standaloneSetup(Object... controllers) { - StandaloneMockMvcBuilder builder = MockMvcBuilders.standaloneSetup(controllers); - return new DefaultMockServerBuilder<>(builder); + static StandaloneSetupBuilder bindToController(Object... controllers) { + return new DefaultRestTestClientBuilder.DefaultStandaloneSetupBuilder(controllers); } /** @@ -138,9 +138,8 @@ public interface RestTestClient { * {@link org.springframework.test.web.servlet.setup.MockMvcBuilders#routerFunctions(RouterFunction[])} * to initialize {@link MockMvc}. */ - static MockServerBuilder bindToRouterFunction(RouterFunction... routerFunctions) { - RouterFunctionMockMvcBuilder builder = MockMvcBuilders.routerFunctions(routerFunctions); - return new DefaultMockServerBuilder<>(builder); + static RouterFunctionSetupBuilder bindToRouterFunction(RouterFunction... routerFunctions) { + return new DefaultRestTestClientBuilder.DefaultRouterFunctionSetupBuilder(routerFunctions); } /** @@ -151,16 +150,15 @@ public interface RestTestClient { * {@link org.springframework.test.web.servlet.setup.MockMvcBuilders#webAppContextSetup(WebApplicationContext)} * to initialize {@code MockMvc}. */ - static MockServerBuilder bindToApplicationContext(WebApplicationContext context) { - DefaultMockMvcBuilder builder = MockMvcBuilders.webAppContextSetup(context); - return new DefaultMockServerBuilder<>(builder); + static WebAppContextSetupBuilder bindToApplicationContext(WebApplicationContext context) { + return new DefaultRestTestClientBuilder.DefaultWebAppContextSetupBuilder(context); } /** * Begin creating a {@link RestTestClient} by providing an already * initialized {@link MockMvc} instance to use as the server. */ - static > Builder bindTo(MockMvc mockMvc) { + static Builder bindTo(MockMvc mockMvc) { ClientHttpRequestFactory requestFactory = new MockMvcClientHttpRequestFactory(mockMvc); return RestTestClient.bindToServer(requestFactory); } @@ -175,7 +173,7 @@ public interface RestTestClient { * * @return chained API to customize client config */ - static > Builder bindToServer() { + static Builder bindToServer() { return new DefaultRestTestClientBuilder<>(); } @@ -183,7 +181,7 @@ public interface RestTestClient { * A variant of {@link #bindToServer()} with a pre-configured request factory. * @return chained API to customize client config */ - static > Builder bindToServer(ClientHttpRequestFactory requestFactory) { + static Builder bindToServer(ClientHttpRequestFactory requestFactory) { return new DefaultRestTestClientBuilder<>(RestClient.builder().requestFactory(requestFactory)); } @@ -195,20 +193,20 @@ public interface RestTestClient { * {@link RestClient#create(String) * WebClient.create(String)}. */ - Builder baseUrl(String baseUrl); + T baseUrl(String baseUrl); /** * Provide a pre-configured {@link UriBuilderFactory} instance as an * alternative to and effectively overriding {@link #baseUrl(String)}. */ - Builder uriBuilderFactory(UriBuilderFactory uriBuilderFactory); + T uriBuilderFactory(UriBuilderFactory uriBuilderFactory); /** * Add the given header to all requests that haven't added it. * @param headerName the header name * @param headerValues the header values */ - Builder defaultHeader(String headerName, String... headerValues); + T defaultHeader(String headerName, String... headerValues); /** * Manipulate the default headers with the given consumer. The @@ -219,14 +217,14 @@ public interface RestTestClient { * @param headersConsumer a function that consumes the {@code HttpHeaders} * @return this builder */ - Builder defaultHeaders(Consumer headersConsumer); + T defaultHeaders(Consumer headersConsumer); /** * Add the given cookie to all requests. * @param cookieName the cookie name * @param cookieValues the cookie values */ - Builder defaultCookie(String cookieName, String... cookieValues); + T defaultCookie(String cookieName, String... cookieValues); /** * Manipulate the default cookies with the given consumer. The @@ -237,29 +235,41 @@ public interface RestTestClient { * @param cookiesConsumer a function that consumes the cookies map * @return this builder */ - Builder defaultCookies(Consumer> cookiesConsumer); + T defaultCookies(Consumer> cookiesConsumer); /** * Apply the given {@code Consumer} to this builder instance. *

This can be useful for applying pre-packaged customizations. * @param builderConsumer the consumer to apply */ - Builder apply(Consumer> builderConsumer); + T apply(Consumer> builderConsumer); /** * Build the {@link RestTestClient} instance. */ RestTestClient build(); + } + + + interface MockMvcSetupBuilder, M extends MockMvcBuilder> extends Builder { + + T configureServer(Consumer consumer); } - interface MockServerBuilder extends Builder> { - - MockServerBuilder configureServer(Consumer consumer); - + interface StandaloneSetupBuilder extends MockMvcSetupBuilder { } + interface RouterFunctionSetupBuilder extends MockMvcSetupBuilder { + } + + + interface WebAppContextSetupBuilder extends MockMvcSetupBuilder { + } + + + /** * Specification for providing the URI of a request. * diff --git a/spring-test/src/test/java/org/springframework/test/web/servlet/client/JsonPathAssertionTests.java b/spring-test/src/test/java/org/springframework/test/web/servlet/client/JsonPathAssertionTests.java index c4993e0a1f2..a63e649418d 100644 --- a/spring-test/src/test/java/org/springframework/test/web/servlet/client/JsonPathAssertionTests.java +++ b/spring-test/src/test/java/org/springframework/test/web/servlet/client/JsonPathAssertionTests.java @@ -48,7 +48,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. class JsonPathAssertionTests { private final RestTestClient client = - RestTestClient.standaloneSetup(new MusicController()) + RestTestClient.bindToController(new MusicController()) .configureServer(builder -> builder.alwaysExpect(status().isOk()) .alwaysExpect(content().contentType(MediaType.APPLICATION_JSON)) diff --git a/spring-test/src/test/java/org/springframework/test/web/servlet/client/samples/ErrorTests.java b/spring-test/src/test/java/org/springframework/test/web/servlet/client/samples/ErrorTests.java index 9c28d6ee55b..656da349f85 100644 --- a/spring-test/src/test/java/org/springframework/test/web/servlet/client/samples/ErrorTests.java +++ b/spring-test/src/test/java/org/springframework/test/web/servlet/client/samples/ErrorTests.java @@ -30,7 +30,7 @@ import org.springframework.web.bind.annotation.RestController; */ class ErrorTests { - private final RestTestClient client = RestTestClient.standaloneSetup(new TestController()).build(); + private final RestTestClient client = RestTestClient.bindToController(new TestController()).build(); @Test diff --git a/spring-test/src/test/java/org/springframework/test/web/servlet/client/samples/HeaderAndCookieTests.java b/spring-test/src/test/java/org/springframework/test/web/servlet/client/samples/HeaderAndCookieTests.java index df60e53ff1e..28a3c99cacb 100644 --- a/spring-test/src/test/java/org/springframework/test/web/servlet/client/samples/HeaderAndCookieTests.java +++ b/spring-test/src/test/java/org/springframework/test/web/servlet/client/samples/HeaderAndCookieTests.java @@ -34,7 +34,7 @@ import org.springframework.web.bind.annotation.RestController; */ class HeaderAndCookieTests { - private final RestTestClient client = RestTestClient.standaloneSetup(new TestController()).build(); + private final RestTestClient client = RestTestClient.bindToController(new TestController()).build(); @Test void requestResponseHeaderPair() { diff --git a/spring-test/src/test/java/org/springframework/test/web/servlet/client/samples/JsonContentTests.java b/spring-test/src/test/java/org/springframework/test/web/servlet/client/samples/JsonContentTests.java index cefb95be673..fc035c1e805 100644 --- a/spring-test/src/test/java/org/springframework/test/web/servlet/client/samples/JsonContentTests.java +++ b/spring-test/src/test/java/org/springframework/test/web/servlet/client/samples/JsonContentTests.java @@ -42,7 +42,7 @@ import static org.hamcrest.Matchers.containsString; */ class JsonContentTests { - private final RestTestClient client = RestTestClient.standaloneSetup(new PersonController()).build(); + private final RestTestClient client = RestTestClient.bindToController(new PersonController()).build(); @Test diff --git a/spring-test/src/test/java/org/springframework/test/web/servlet/client/samples/ResponseEntityTests.java b/spring-test/src/test/java/org/springframework/test/web/servlet/client/samples/ResponseEntityTests.java index 20d2c5385ac..12596a25936 100644 --- a/spring-test/src/test/java/org/springframework/test/web/servlet/client/samples/ResponseEntityTests.java +++ b/spring-test/src/test/java/org/springframework/test/web/servlet/client/samples/ResponseEntityTests.java @@ -43,7 +43,7 @@ import static org.hamcrest.Matchers.startsWith; * @author Rob Worsnop */ class ResponseEntityTests { - private final RestTestClient client = RestTestClient.standaloneSetup(new PersonController()) + private final RestTestClient client = RestTestClient.bindToController(new PersonController()) .baseUrl("/persons") .build(); diff --git a/spring-test/src/test/java/org/springframework/test/web/servlet/client/samples/RestTestClientTests.java b/spring-test/src/test/java/org/springframework/test/web/servlet/client/samples/RestTestClientTests.java index 5477ec670cf..381c520ca7f 100644 --- a/spring-test/src/test/java/org/springframework/test/web/servlet/client/samples/RestTestClientTests.java +++ b/spring-test/src/test/java/org/springframework/test/web/servlet/client/samples/RestTestClientTests.java @@ -53,7 +53,7 @@ class RestTestClientTests { @BeforeEach void setUp() { - this.client = RestTestClient.standaloneSetup(new TestController()).build(); + this.client = RestTestClient.bindToController(new TestController()).build(); } @Nested diff --git a/spring-test/src/test/java/org/springframework/test/web/servlet/client/samples/SoftAssertionTests.java b/spring-test/src/test/java/org/springframework/test/web/servlet/client/samples/SoftAssertionTests.java index a9f433c21ec..d13154e857f 100644 --- a/spring-test/src/test/java/org/springframework/test/web/servlet/client/samples/SoftAssertionTests.java +++ b/spring-test/src/test/java/org/springframework/test/web/servlet/client/samples/SoftAssertionTests.java @@ -30,7 +30,7 @@ import static org.assertj.core.api.Assertions.assertThatExceptionOfType; */ class SoftAssertionTests { - private final RestTestClient restTestClient = RestTestClient.standaloneSetup(new TestController()).build(); + private final RestTestClient restTestClient = RestTestClient.bindToController(new TestController()).build(); @Test diff --git a/spring-test/src/test/java/org/springframework/test/web/servlet/client/samples/XmlContentTests.java b/spring-test/src/test/java/org/springframework/test/web/servlet/client/samples/XmlContentTests.java index 8950f51bed4..f9af1bcaa45 100644 --- a/spring-test/src/test/java/org/springframework/test/web/servlet/client/samples/XmlContentTests.java +++ b/spring-test/src/test/java/org/springframework/test/web/servlet/client/samples/XmlContentTests.java @@ -58,7 +58,7 @@ class XmlContentTests { """; - private final RestTestClient client = RestTestClient.standaloneSetup(new PersonController()).build(); + private final RestTestClient client = RestTestClient.bindToController(new PersonController()).build(); @Test diff --git a/spring-test/src/test/java/org/springframework/test/web/servlet/client/samples/bind/ControllerTests.java b/spring-test/src/test/java/org/springframework/test/web/servlet/client/samples/bind/ControllerTests.java index 2f2aaee064c..227bdc0d3d7 100644 --- a/spring-test/src/test/java/org/springframework/test/web/servlet/client/samples/bind/ControllerTests.java +++ b/spring-test/src/test/java/org/springframework/test/web/servlet/client/samples/bind/ControllerTests.java @@ -36,7 +36,7 @@ class ControllerTests { @BeforeEach void setUp() { - this.client = RestTestClient.standaloneSetup(new TestController()).build(); + this.client = RestTestClient.bindToController(new TestController()).build(); }