Skip to content

Add web test client restdocs autoconfiguration #10969

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 13 commits into from
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@
<module name="com.puppycrawl.tools.checkstyle.checks.imports.AvoidStarImportCheck" />
<module name="com.puppycrawl.tools.checkstyle.checks.imports.AvoidStaticImportCheck">
<property name="excludes"
value="io.restassured.RestAssured.*, org.assertj.core.api.Assertions.*, org.junit.Assert.*, org.junit.Assume.*, org.junit.internal.matchers.ThrowableMessageMatcher.*, org.hamcrest.CoreMatchers.*, org.hamcrest.Matchers.*, org.springframework.boot.configurationprocessor.ConfigurationMetadataMatchers.*, org.springframework.boot.configurationprocessor.TestCompiler.*, org.springframework.boot.test.autoconfigure.AutoConfigurationImportedCondition.*, org.mockito.Mockito.*, org.mockito.BDDMockito.*, org.mockito.ArgumentMatchers.*, org.mockito.Matchers.*, org.springframework.restdocs.hypermedia.HypermediaDocumentation.*, org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.*, org.springframework.restdocs.operation.preprocess.Preprocessors.*, org.springframework.restdocs.restassured3.operation.preprocess.RestAssuredPreprocessors.*, org.springframework.restdocs.restassured3.RestAssuredRestDocumentation.*, org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*, org.springframework.test.web.servlet.result.MockMvcResultMatchers.*, org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.*, org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.*, org.springframework.hateoas.mvc.ControllerLinkBuilder.linkTo, org.springframework.test.web.client.ExpectedCount.*, org.springframework.test.web.client.match.MockRestRequestMatchers.*, org.springframework.test.web.client.response.MockRestResponseCreators.*" />
value="io.restassured.RestAssured.*, org.assertj.core.api.Assertions.*, org.junit.Assert.*, org.junit.Assume.*, org.junit.internal.matchers.ThrowableMessageMatcher.*, org.hamcrest.CoreMatchers.*, org.hamcrest.Matchers.*, org.springframework.boot.configurationprocessor.ConfigurationMetadataMatchers.*, org.springframework.boot.configurationprocessor.TestCompiler.*, org.springframework.boot.test.autoconfigure.AutoConfigurationImportedCondition.*, org.mockito.Mockito.*, org.mockito.BDDMockito.*, org.mockito.ArgumentMatchers.*, org.mockito.Matchers.*, org.springframework.restdocs.hypermedia.HypermediaDocumentation.*, org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.*, org.springframework.restdocs.webtestclient.WebTestClientRestDocumentation.*, org.springframework.restdocs.operation.preprocess.Preprocessors.*, org.springframework.restdocs.restassured3.operation.preprocess.RestAssuredPreprocessors.*, org.springframework.restdocs.restassured3.RestAssuredRestDocumentation.*, org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*, org.springframework.test.web.servlet.result.MockMvcResultMatchers.*, org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.*, org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.*, org.springframework.hateoas.mvc.ControllerLinkBuilder.linkTo, org.springframework.test.web.client.ExpectedCount.*, org.springframework.test.web.client.match.MockRestRequestMatchers.*, org.springframework.test.web.client.response.MockRestResponseCreators.*" />
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added org.springframework.restdocs.webtestclient.WebTestClientRestDocumentation.*

</module>
<module name="com.puppycrawl.tools.checkstyle.checks.imports.IllegalImportCheck" >
<property name="illegalPkgs" value="com.google.common"/>
Expand Down
5 changes: 5 additions & 0 deletions spring-boot-project/spring-boot-test-autoconfigure/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,11 @@
<artifactId>spring-restdocs-restassured</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.restdocs</groupId>
<artifactId>spring-restdocs-webtestclient</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,15 @@
import org.springframework.restdocs.mockmvc.RestDocumentationResultHandler;
import org.springframework.restdocs.restassured3.RestAssuredRestDocumentation;
import org.springframework.restdocs.restassured3.RestAssuredRestDocumentationConfigurer;
import org.springframework.restdocs.webtestclient.WebTestClientRestDocumentation;
import org.springframework.restdocs.webtestclient.WebTestClientRestDocumentationConfigurer;

/**
* {@link EnableAutoConfiguration Auto-configuration} for Spring REST Docs.
*
* @author Andy Wilkinson
* @author Eddú Meléndez
* @author Roman Zaynetdinov
* @since 1.4.0
*/
@Configuration
Expand Down Expand Up @@ -108,4 +111,33 @@ public RestDocsRestAssuredBuilderCustomizer restAssuredBuilderCustomizer(

}

@Configuration
@ConditionalOnClass(WebTestClientRestDocumentation.class)
@ConditionalOnWebApplication(type = Type.REACTIVE)
static class RestDocsWebTestClientAutoConfiguration {

@Bean
@ConditionalOnMissingBean(WebTestClientRestDocumentationConfigurer.class)
public WebTestClientRestDocumentationConfigurer restDocsWebTestClientConfigurer(
ObjectProvider<RestDocsWebTestClientConfigurationCustomizer> configurationCustomizerProvider,
RestDocumentationContextProvider contextProvider) {
WebTestClientRestDocumentationConfigurer configurer = WebTestClientRestDocumentation
.documentationConfiguration(contextProvider);
RestDocsWebTestClientConfigurationCustomizer configurationCustomizer = configurationCustomizerProvider
.getIfAvailable();
if (configurationCustomizer != null) {
configurationCustomizer.customize(configurer);
}
return configurer;
}

@Bean
@ConfigurationProperties(prefix = "spring.test.restdocs")
public RestDocsWebTestClientBuilderCustomizer restDocumentationConfigurer(
WebTestClientRestDocumentationConfigurer configurer) {
return new RestDocsWebTestClientBuilderCustomizer(configurer);
}

}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
/*
* Copyright 2012-2017 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
*
* http://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.test.autoconfigure.restdocs;

import org.springframework.beans.factory.InitializingBean;
import org.springframework.boot.test.autoconfigure.web.reactive.WebTestClientBuilderCustomizer;
import org.springframework.restdocs.webtestclient.WebTestClientRestDocumentationConfigurer;
import org.springframework.test.web.reactive.server.WebTestClient;
import org.springframework.util.StringUtils;

/**
* A customizer that configures Spring REST Docs with WebTestClient.
*
* @author Eddú Meléndez
* @author Roman Zaynetdinov
*/
class RestDocsWebTestClientBuilderCustomizer implements InitializingBean, WebTestClientBuilderCustomizer {

private final WebTestClientRestDocumentationConfigurer delegate;

private String uriScheme;

private String uriHost;

private Integer uriPort;

RestDocsWebTestClientBuilderCustomizer(WebTestClientRestDocumentationConfigurer delegate) {
this.delegate = delegate;
}

public String getUriScheme() {
return this.uriScheme;
}

public void setUriScheme(String uriScheme) {
this.uriScheme = uriScheme;
}

public String getUriHost() {
return this.uriHost;
}

public void setUriHost(String uriHost) {
this.uriHost = uriHost;
}

public Integer getUriPort() {
return this.uriPort;
}

public void setUriPort(Integer uriPort) {
this.uriPort = uriPort;
}

@Override
public void afterPropertiesSet() throws Exception {
}

@Override
public void customize(WebTestClient.Builder builder) {
if (StringUtils.hasText(this.uriScheme) && StringUtils.hasText(this.uriHost)) {
String baseUrl = this.uriScheme + "://" + this.uriHost;

if (this.uriPort == 80 && this.uriScheme.equals("http")) {
// Don't add default port
} else if (this.uriPort == 443 && this.uriScheme.equals("https")) {
// Don't add default port
} else if (this.uriPort != null) {
baseUrl += ":" + this.uriPort;
}

builder.baseUrl(baseUrl);
}
builder.filter(this.delegate);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
* Copyright 2012-2017 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
*
* http://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.test.autoconfigure.restdocs;

import org.springframework.restdocs.webtestclient.WebTestClientRestDocumentationConfigurer;

/**
* A customizer for {@link WebTestClientRestDocumentationConfigurer}. If a
* {@code RestDocsWebTestClientConfigurationCustomizer} bean is found in the application context
* it will be {@link #customize called} to customize the
* {@code WebTestClientRestDocumentationConfigurer} before it is applied. Intended for use only
* when the attributes on {@link AutoConfigureRestDocs} do not provide sufficient
* customization.
*
* @author Andy Wilkinson
* @author Roman Zaynetdinov
* @since 2.0.0
*/
@FunctionalInterface
public interface RestDocsWebTestClientConfigurationCustomizer {

/**
* Customize the given {@code configurer}.
* @param configurer the configurer
*/
void customize(WebTestClientRestDocumentationConfigurer configurer);

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/*
* Copyright 2012-2017 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
*
* http://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.test.autoconfigure.web.reactive;

import java.time.Duration;
import java.util.Collection;
import java.util.function.Consumer;

import org.springframework.boot.context.properties.bind.Binder;
import org.springframework.boot.web.codec.CodecCustomizer;
import org.springframework.context.ApplicationContext;
import org.springframework.http.codec.ClientCodecConfigurer;
import org.springframework.test.web.reactive.server.WebTestClient;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.web.reactive.function.client.ExchangeStrategies;

/**
* {@link WebTestClientBuilderCustomizer} for a typical Spring Boot application. Usually applied
* automatically via {@link AutoConfigureWebTestClient @AutoConfigureWebTestClient}, but may also be
* used directly.
*
* @author Phillip Webb
* @author Andy Wilkinson
* @author Roman Zaynetdinov
* @since 2.0.0
*/
public class SpringBootWebTestClientBuilderCustomizer implements WebTestClientBuilderCustomizer {

private final ApplicationContext context;

/**
* Create a new {@link SpringBootWebTestClientBuilderCustomizer} instance.
* @param context the source application context
*/
public SpringBootWebTestClientBuilderCustomizer(ApplicationContext context) {
Assert.notNull(context, "Context must not be null");
this.context = context;
}

@Override
public void customize(WebTestClient.Builder builder) {
customizeWebTestClient(builder);
customizeWebTestClientCodecs(builder);
}

private void customizeWebTestClient(WebTestClient.Builder builder) {
Binder.get(this.context.getEnvironment())
.bind("spring.test.webtestclient.timeout", Duration.class)
.ifBound(builder::responseTimeout);
}

private void customizeWebTestClientCodecs(WebTestClient.Builder builder) {
Collection<CodecCustomizer> customizers = this.context
.getBeansOfType(CodecCustomizer.class).values();
if (!CollectionUtils.isEmpty(customizers)) {
builder.exchangeStrategies(ExchangeStrategies.builder()
.codecs(this.applyCustomizers(customizers)).build());
}
}

private Consumer<ClientCodecConfigurer> applyCustomizers(
Collection<CodecCustomizer> customizers) {
return (codecs) -> customizers
.forEach((customizer) -> customizer.customize(codecs));
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -16,68 +16,50 @@

package org.springframework.boot.test.autoconfigure.web.reactive;

import java.time.Duration;
import java.util.Collection;
import java.util.function.Consumer;
import java.util.List;

import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.http.codec.CodecsAutoConfiguration;
import org.springframework.boot.context.properties.bind.Binder;
import org.springframework.boot.web.codec.CodecCustomizer;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.codec.ClientCodecConfigurer;
import org.springframework.test.web.reactive.server.WebTestClient;
import org.springframework.test.web.reactive.server.WebTestClient.Builder;
import org.springframework.util.CollectionUtils;
import org.springframework.web.reactive.function.client.ExchangeStrategies;
import org.springframework.web.reactive.function.client.WebClient;

/**
* Auto-configuration for {@link WebTestClient}.
*
* @author Stephane Nicoll
* @author Roman Zaynetdinov
* @since 2.0.0
*/
@Configuration
@ConditionalOnClass({ WebClient.class, WebTestClient.class })
@AutoConfigureAfter(CodecsAutoConfiguration.class)
public class WebTestClientAutoConfiguration {

@Bean
@ConditionalOnMissingBean
public WebTestClient webTestClient(ApplicationContext applicationContext) {
WebTestClient.Builder builder = WebTestClient
.bindToApplicationContext(applicationContext).configureClient();
customizeWebTestClient(builder, applicationContext);
customizeWebTestClientCodecs(builder, applicationContext);
return builder.build();
}
private final ApplicationContext context;

private void customizeWebTestClient(Builder builder,
ApplicationContext applicationContext) {
Binder.get(applicationContext.getEnvironment())
.bind("spring.test.webtestclient.timeout", Duration.class)
.ifBound(builder::responseTimeout);
WebTestClientAutoConfiguration(ApplicationContext context) {
this.context = context;
}

private void customizeWebTestClientCodecs(WebTestClient.Builder builder,
ApplicationContext applicationContext) {
Collection<CodecCustomizer> customizers = applicationContext
.getBeansOfType(CodecCustomizer.class).values();
if (!CollectionUtils.isEmpty(customizers)) {
builder.exchangeStrategies(ExchangeStrategies.builder()
.codecs(applyCustomizers(customizers)).build());
@Bean
@ConditionalOnMissingBean
public WebTestClient webTestClient(List<WebTestClientBuilderCustomizer> customizers) {
WebTestClient.Builder builder = WebTestClient
.bindToApplicationContext(this.context).configureClient();
for (WebTestClientBuilderCustomizer customizer : customizers) {
customizer.customize(builder);
}
return builder.build();
}

private Consumer<ClientCodecConfigurer> applyCustomizers(
Collection<CodecCustomizer> customizers) {
return (codecs) -> customizers
.forEach((customizer) -> customizer.customize(codecs));
@Bean
public SpringBootWebTestClientBuilderCustomizer springBootWebTestClientBuilderCustomizer() {
return new SpringBootWebTestClientBuilderCustomizer(this.context);
}

}
Loading