Add support for Mock test with WebFlux

This commit add mock support for WebFlux with an infrastructure similar
to what `WebMvcTest` provides. `@WebFluxTest` can be used to test
controllers with a narrowed classpath that is relevant to WebFlux. Also,
`@SpringBootTest` now starts WebFlux in "mock" mode by default and
`@AutoConfigureWebTestClient` can be used to inject a `WebTestClient`
connected to the `ApplicationContext`.

To make that happen, a `ReactiveWebApplicationContext` interface has been
introduced to mirror what `WebApplicationContext` currently does. Things
are still a bit volatile at this point and that infra may move to Spring
Framework at some point.

Closes gh-8401
This commit is contained in:
Stephane Nicoll
2017-02-24 17:13:14 +01:00
parent 30564eb619
commit c5595f296c
37 changed files with 1123 additions and 36 deletions

View File

@@ -23,10 +23,11 @@ import org.springframework.test.context.MergedContextConfiguration;
* all of its superclasses for a reactive web application.
*
* @author Stephane Nicoll
* @since 2.0.0
*/
class ReactiveWebMergedContextConfiguration extends MergedContextConfiguration {
public class ReactiveWebMergedContextConfiguration extends MergedContextConfiguration {
ReactiveWebMergedContextConfiguration(
public ReactiveWebMergedContextConfiguration(
MergedContextConfiguration mergedConfig) {
super(mergedConfig);
}

View File

@@ -28,6 +28,7 @@ import org.springframework.beans.BeanUtils;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.WebApplicationType;
import org.springframework.boot.bind.RelaxedPropertyResolver;
import org.springframework.boot.context.GenericReactiveWebApplicationContext;
import org.springframework.boot.test.mock.web.SpringBootMockServletContext;
import org.springframework.boot.test.util.EnvironmentTestUtils;
import org.springframework.boot.web.support.ServletContextApplicationContextInitializer;
@@ -116,6 +117,9 @@ public class SpringBootContextLoader extends AbstractContextLoader {
}
else if (config instanceof ReactiveWebMergedContextConfiguration) {
application.setWebApplicationType(WebApplicationType.REACTIVE);
if (!isEmbeddedWebEnvironment(config)) {
new ReactiveWebConfigurer().configure(application);
}
}
else {
application.setWebApplicationType(WebApplicationType.NONE);
@@ -281,6 +285,19 @@ public class SpringBootContextLoader extends AbstractContextLoader {
}
/**
* Inner class to configure {@link ReactiveWebMergedContextConfiguration}.
*/
private static class ReactiveWebConfigurer {
private static final Class<GenericReactiveWebApplicationContext> WEB_CONTEXT_CLASS = GenericReactiveWebApplicationContext.class;
void configure(SpringApplication application) {
application.setApplicationContextClass(WEB_CONTEXT_CLASS);
}
}
/**
* Adapts a {@link ContextCustomizer} to a {@link ApplicationContextInitializer} so
* that it can be triggered via {@link SpringApplication}.

View File

@@ -164,8 +164,8 @@ public class SpringBootTestContextBootstrapper extends DefaultTestContextBootstr
mergedConfig = new WebMergedContextConfiguration(mergedConfig,
resourceBasePath);
}
else if (webApplicationType == WebApplicationType.REACTIVE
&& webEnvironment.isEmbedded()) {
else if (webApplicationType == WebApplicationType.REACTIVE &&
(webEnvironment.isEmbedded() || webEnvironment == WebEnvironment.MOCK)) {
return new ReactiveWebMergedContextConfiguration(mergedConfig);
}
}

View File

@@ -21,8 +21,8 @@ import reactor.core.publisher.Mono;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.ReactiveWebApplicationContext;
import org.springframework.boot.context.embedded.LocalServerPort;
import org.springframework.boot.context.embedded.ReactiveWebApplicationContext;
import org.springframework.boot.context.embedded.ReactiveWebServerFactory;
import org.springframework.boot.context.embedded.tomcat.TomcatReactiveWebServerFactory;
import org.springframework.context.ApplicationContext;