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:
parent
a1fe82c3dd
commit
8b3bea173c
|
@ -172,8 +172,9 @@ include::{docs-java}/features/testing/springbootapplications/usingapplicationarg
|
|||
|
||||
[[features.testing.spring-boot-applications.with-mock-environment]]
|
||||
==== Testing with a mock environment
|
||||
By default, `@SpringBootTest` does not start the server.
|
||||
If you have web endpoints that you want to test against this mock environment, you can additionally configure {spring-framework-docs}/testing.html#spring-mvc-test-framework[`MockMvc`] as shown in the following example:
|
||||
By default, `@SpringBootTest` does not start the server but instead sets up a mock environment for testing web endpoints.
|
||||
|
||||
With Spring MVC, we can query our web endpoints using {spring-framework-docs}/testing.html#spring-mvc-test-framework[`MockMvc`] or `WebTestClient`, as shown in the following example:
|
||||
|
||||
[source,java,indent=0,subs="verbatim"]
|
||||
----
|
||||
|
@ -182,7 +183,7 @@ include::{docs-java}/features/testing/springbootapplications/withmockenvironment
|
|||
|
||||
TIP: If you want to focus only on the web layer and not start a complete `ApplicationContext`, consider <<features#features.testing.spring-boot-applications.spring-mvc-tests,using `@WebMvcTest` instead>>.
|
||||
|
||||
Alternatively, you can configure a {spring-framework-docs}/testing.html#webtestclient-tests[`WebTestClient`] as shown in the following example:
|
||||
With Spring WebFlux endpoints, you can use {spring-framework-docs}/testing.html#webtestclient-tests[`WebTestClient`] as shown in the following example:
|
||||
|
||||
[source,java,indent=0,subs="verbatim"]
|
||||
----
|
||||
|
@ -214,6 +215,8 @@ For convenience, tests that need to make REST calls to the started server can ad
|
|||
include::{docs-java}/features/testing/springbootapplications/withrunningserver/MyRandomPortWebTestClientTests.java[]
|
||||
----
|
||||
|
||||
TIP: `WebTestClient` can be used against both live servers and <<features#features.testing.spring-boot-applications.with-mock-environment, mock environments>>.
|
||||
|
||||
This setup requires `spring-webflux` on the classpath.
|
||||
If you can't or won't add webflux, Spring Boot also provides a `TestRestTemplate` facility:
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@ import org.junit.jupiter.api.Test;
|
|||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.test.web.reactive.server.WebTestClient;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
|
@ -32,8 +33,20 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
|
|||
class MyMockMvcTests {
|
||||
|
||||
@Test
|
||||
void exampleTest(@Autowired MockMvc mvc) throws Exception {
|
||||
void testWithMockMvc(@Autowired MockMvc mvc) throws Exception {
|
||||
mvc.perform(get("/")).andExpect(status().isOk()).andExpect(content().string("Hello World"));
|
||||
}
|
||||
|
||||
// If Spring WebFlux is on the classpath, you can drive MVC tests with a WebTestClient
|
||||
@Test
|
||||
void testWithWebTestClient(@Autowired WebTestClient webClient) {
|
||||
// @formatter:off
|
||||
webClient
|
||||
.get().uri("/")
|
||||
.exchange()
|
||||
.expectStatus().isOk()
|
||||
.expectBody(String.class).isEqualTo("Hello World");
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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=\
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue