11/*
2- * Copyright 2012-2019 the original author or authors.
2+ * Copyright 2012-2021 the original author or authors.
33 *
44 * Licensed under the Apache License, Version 2.0 (the "License");
55 * you may not use this file except in compliance with the License.
3030import org .springframework .beans .factory .support .BeanDefinitionRegistry ;
3131import org .springframework .beans .factory .support .BeanDefinitionRegistryPostProcessor ;
3232import org .springframework .beans .factory .support .RootBeanDefinition ;
33+ import org .springframework .boot .WebApplicationType ;
3334import org .springframework .boot .test .context .SpringBootTest ;
3435import org .springframework .boot .test .context .SpringBootTest .WebEnvironment ;
3536import org .springframework .boot .web .codec .CodecCustomizer ;
4546import org .springframework .test .context .ContextCustomizer ;
4647import org .springframework .test .context .MergedContextConfiguration ;
4748import org .springframework .test .web .reactive .server .WebTestClient ;
49+ import org .springframework .util .ClassUtils ;
4850import org .springframework .util .CollectionUtils ;
51+ import org .springframework .util .StringUtils ;
52+ import org .springframework .web .context .WebApplicationContext ;
4953import org .springframework .web .reactive .function .client .ExchangeStrategies ;
5054
5155/**
@@ -132,6 +136,10 @@ public static class WebTestClientFactory implements FactoryBean<WebTestClient>,
132136
133137 private WebTestClient object ;
134138
139+ private static final String SERVLET_APPLICATION_CONTEXT_CLASS = "org.springframework.web.context.WebApplicationContext" ;
140+
141+ private static final String REACTIVE_APPLICATION_CONTEXT_CLASS = "org.springframework.boot.web.reactive.context.ReactiveWebApplicationContext" ;
142+
135143 @ Override
136144 public void setApplicationContext (ApplicationContext applicationContext ) throws BeansException {
137145 this .applicationContext = applicationContext ;
@@ -158,13 +166,49 @@ public WebTestClient getObject() throws Exception {
158166 private WebTestClient createWebTestClient () {
159167 boolean sslEnabled = isSslEnabled (this .applicationContext );
160168 String port = this .applicationContext .getEnvironment ().getProperty ("local.server.port" , "8080" );
161- String baseUrl = (sslEnabled ? "https" : "http" ) + "://localhost:" + port ;
169+ String baseUrl = getBaseUrl (sslEnabled , port ) ;
162170 WebTestClient .Builder builder = WebTestClient .bindToServer ();
163171 customizeWebTestClientBuilder (builder , this .applicationContext );
164172 customizeWebTestClientCodecs (builder , this .applicationContext );
165173 return builder .baseUrl (baseUrl ).build ();
166174 }
167175
176+ private String getBaseUrl (boolean sslEnabled , String port ) {
177+ String basePath = deduceBasePath ();
178+ String pathSegment = (StringUtils .hasText (basePath )) ? basePath : "" ;
179+ return (sslEnabled ? "https" : "http" ) + "://localhost:" + port + pathSegment ;
180+ }
181+
182+ private String deduceBasePath () {
183+ WebApplicationType webApplicationType = deduceFromApplicationContext (this .applicationContext .getClass ());
184+ if (webApplicationType == WebApplicationType .REACTIVE ) {
185+ return this .applicationContext .getEnvironment ().getProperty ("spring.webflux.base-path" );
186+ }
187+ else if (webApplicationType == WebApplicationType .SERVLET ) {
188+ return ((WebApplicationContext ) this .applicationContext ).getServletContext ().getContextPath ();
189+ }
190+ return null ;
191+ }
192+
193+ static WebApplicationType deduceFromApplicationContext (Class <?> applicationContextClass ) {
194+ if (isAssignable (SERVLET_APPLICATION_CONTEXT_CLASS , applicationContextClass )) {
195+ return WebApplicationType .SERVLET ;
196+ }
197+ if (isAssignable (REACTIVE_APPLICATION_CONTEXT_CLASS , applicationContextClass )) {
198+ return WebApplicationType .REACTIVE ;
199+ }
200+ return WebApplicationType .NONE ;
201+ }
202+
203+ private static boolean isAssignable (String target , Class <?> type ) {
204+ try {
205+ return ClassUtils .resolveClassName (target , null ).isAssignableFrom (type );
206+ }
207+ catch (Throwable ex ) {
208+ return false ;
209+ }
210+ }
211+
168212 private boolean isSslEnabled (ApplicationContext context ) {
169213 try {
170214 AbstractReactiveWebServerFactory webServerFactory = context
0 commit comments