Configure WebTestClient for @AutoConfigureMockMvc tests

As of Spring Framework 5.3, `WebTestClient` can now be configured on top
of `MockMvc` for testing Spring MVC applications in a mock environment.

Prior to this commit, `WebTestClient` would be already configured for
WebFlux mock setups with `@AutoConfigureWebTestClient` or live servers
(for both MVC and WebFlux apps).

This commit enhances the `@AutoConfigureWebMvc` support so that a
`WebTestClient` instance is auto-configured if the spring-webflux
dependency is present on the classpath.

Closes gh-23067
This commit is contained in:
Brian Clozel
2021-08-03 09:43:44 +02:00
parent a1fe82c3dd
commit 8b3bea173c
6 changed files with 96 additions and 9 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2019 the original author or authors.
* Copyright 2012-2021 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.
@@ -19,6 +19,7 @@ package org.springframework.boot.test.autoconfigure.web.servlet;
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.condition.ConditionalOnWebApplication;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;
@@ -28,14 +29,19 @@ import org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguratio
import org.springframework.boot.autoconfigure.web.servlet.WebMvcProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.test.autoconfigure.web.reactive.WebTestClientAutoConfiguration;
import org.springframework.boot.test.web.reactive.server.WebTestClientBuilderCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.test.web.reactive.server.WebTestClient;
import org.springframework.test.web.servlet.DispatcherServletCustomizer;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MockMvcBuilder;
import org.springframework.test.web.servlet.client.MockMvcWebTestClient;
import org.springframework.test.web.servlet.setup.DefaultMockMvcBuilder;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.reactive.function.client.WebClient;
import org.springframework.web.servlet.DispatcherServlet;
/**
@@ -44,12 +50,13 @@ import org.springframework.web.servlet.DispatcherServlet;
* @author Phillip Webb
* @author Andy Wilkinson
* @author Stephane Nicoll
* @author Brian Clozel
* @see AutoConfigureWebMvc
* @since 1.4.0
*/
@Configuration(proxyBeanMethods = false)
@ConditionalOnWebApplication(type = Type.SERVLET)
@AutoConfigureAfter(WebMvcAutoConfiguration.class)
@AutoConfigureAfter({ WebMvcAutoConfiguration.class, WebTestClientAutoConfiguration.class })
@EnableConfigurationProperties({ ServerProperties.class, WebMvcProperties.class })
public class MockMvcAutoConfiguration {
@@ -97,6 +104,22 @@ public class MockMvcAutoConfiguration {
return mockMvc.getDispatcherServlet();
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({ WebClient.class, WebTestClient.class })
static class WebTestClientMockMvcConfiguration {
@Bean
@ConditionalOnMissingBean
WebTestClient webTestClient(MockMvc mockMvc, List<WebTestClientBuilderCustomizer> customizers) {
WebTestClient.Builder builder = MockMvcWebTestClient.bindTo(mockMvc);
for (WebTestClientBuilderCustomizer customizer : customizers) {
customizer.customize(builder);
}
return builder.build();
}
}
private static class MockMvcDispatcherServletCustomizer implements DispatcherServletCustomizer {
private final WebMvcProperties webMvcProperties;

View File

@@ -143,7 +143,8 @@ org.springframework.boot.autoconfigure.security.oauth2.resource.servlet.OAuth2Re
org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration,\
org.springframework.boot.autoconfigure.security.servlet.SecurityFilterAutoConfiguration,\
org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration,\
org.springframework.boot.test.autoconfigure.web.servlet.MockMvcSecurityConfiguration
org.springframework.boot.test.autoconfigure.web.servlet.MockMvcSecurityConfiguration,\
org.springframework.boot.test.autoconfigure.web.reactive.WebTestClientAutoConfiguration
# AutoConfigureMockRestServiceServer
org.springframework.boot.test.autoconfigure.web.client.AutoConfigureMockRestServiceServer=\

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2020 the original author or authors.
* Copyright 2012-2021 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.
@@ -19,16 +19,26 @@ package org.springframework.boot.test.autoconfigure.web.servlet;
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.server.WebTestClientBuilderCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.test.web.reactive.server.WebTestClient;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.web.reactive.function.client.WebClient;
import org.springframework.web.servlet.DispatcherServlet;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
/**
* Tests for {@link MockMvcAutoConfiguration}.
*
* @author Madhura Bhave
* @author Brian Clozel
*/
class MockMvcAutoConfigurationTests {
@@ -44,4 +54,35 @@ class MockMvcAutoConfigurationTests {
});
}
@Test
void registersWebTestClient() {
this.contextRunner.run((context) -> assertThat(context).hasSingleBean(WebTestClient.class));
}
@Test
void shouldNotRegisterWebTestClientIfWebFluxMissing() {
this.contextRunner.withClassLoader(new FilteredClassLoader(WebClient.class))
.run((context) -> assertThat(context).doesNotHaveBean(WebTestClient.class));
}
@Test
void shouldApplyWebTestClientCustomizers() {
this.contextRunner.withUserConfiguration(WebTestClientCustomConfig.class).run((context) -> {
assertThat(context).hasSingleBean(WebTestClient.class);
assertThat(context).hasBean("myWebTestClientCustomizer");
verify(context.getBean("myWebTestClientCustomizer", WebTestClientBuilderCustomizer.class))
.customize(any(WebTestClient.Builder.class));
});
}
@Configuration(proxyBeanMethods = false)
static class WebTestClientCustomConfig {
@Bean
WebTestClientBuilderCustomizer myWebTestClientCustomizer() {
return mock(WebTestClientBuilderCustomizer.class);
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2019 the original author or authors.
* Copyright 2012-2021 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.
@@ -28,6 +28,7 @@ import org.springframework.boot.test.system.CapturedOutput;
import org.springframework.boot.test.system.OutputCaptureExtension;
import org.springframework.context.ApplicationContext;
import org.springframework.security.test.context.support.WithMockUser;
import org.springframework.test.web.reactive.server.WebTestClient;
import org.springframework.test.web.servlet.MockMvc;
import static org.assertj.core.api.Assertions.assertThat;
@@ -77,4 +78,9 @@ class MockMvcSpringBootTestIntegrationTests {
assertThat(this.applicationContext.getBean(ExampleRealService.class)).isNotNull();
}
@Test
void shouldTestWithWebTestClient(@Autowired WebTestClient webTestClient) {
webTestClient.get().uri("/one").exchange().expectStatus().isOk().expectBody(String.class).isEqualTo("one");
}
}