11/*
2- * Copyright 2012-2020 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 .web .codec .CodecCustomizer ;
3536import org .springframework .boot .web .reactive .server .AbstractReactiveWebServerFactory ;
4243import org .springframework .test .context .MergedContextConfiguration ;
4344import org .springframework .test .context .TestContextAnnotationUtils ;
4445import org .springframework .test .web .reactive .server .WebTestClient ;
46+ import org .springframework .util .ClassUtils ;
4547import org .springframework .util .CollectionUtils ;
48+ import org .springframework .util .StringUtils ;
49+ import org .springframework .web .context .WebApplicationContext ;
4650import org .springframework .web .reactive .function .client .ExchangeStrategies ;
4751
4852/**
@@ -129,6 +133,10 @@ public static class WebTestClientFactory implements FactoryBean<WebTestClient>,
129133
130134 private WebTestClient object ;
131135
136+ private static final String SERVLET_APPLICATION_CONTEXT_CLASS = "org.springframework.web.context.WebApplicationContext" ;
137+
138+ private static final String REACTIVE_APPLICATION_CONTEXT_CLASS = "org.springframework.boot.web.reactive.context.ReactiveWebApplicationContext" ;
139+
132140 @ Override
133141 public void setApplicationContext (ApplicationContext applicationContext ) throws BeansException {
134142 this .applicationContext = applicationContext ;
@@ -155,13 +163,49 @@ public WebTestClient getObject() throws Exception {
155163 private WebTestClient createWebTestClient () {
156164 boolean sslEnabled = isSslEnabled (this .applicationContext );
157165 String port = this .applicationContext .getEnvironment ().getProperty ("local.server.port" , "8080" );
158- String baseUrl = (sslEnabled ? "https" : "http" ) + "://localhost:" + port ;
166+ String baseUrl = getBaseUrl (sslEnabled , port ) ;
159167 WebTestClient .Builder builder = WebTestClient .bindToServer ();
160168 customizeWebTestClientBuilder (builder , this .applicationContext );
161169 customizeWebTestClientCodecs (builder , this .applicationContext );
162170 return builder .baseUrl (baseUrl ).build ();
163171 }
164172
173+ private String getBaseUrl (boolean sslEnabled , String port ) {
174+ String basePath = deduceBasePath ();
175+ String pathSegment = (StringUtils .hasText (basePath )) ? basePath : "" ;
176+ return (sslEnabled ? "https" : "http" ) + "://localhost:" + port + pathSegment ;
177+ }
178+
179+ private String deduceBasePath () {
180+ WebApplicationType webApplicationType = deduceFromApplicationContext (this .applicationContext .getClass ());
181+ if (webApplicationType == WebApplicationType .REACTIVE ) {
182+ return this .applicationContext .getEnvironment ().getProperty ("spring.webflux.base-path" );
183+ }
184+ else if (webApplicationType == WebApplicationType .SERVLET ) {
185+ return ((WebApplicationContext ) this .applicationContext ).getServletContext ().getContextPath ();
186+ }
187+ return null ;
188+ }
189+
190+ static WebApplicationType deduceFromApplicationContext (Class <?> applicationContextClass ) {
191+ if (isAssignable (SERVLET_APPLICATION_CONTEXT_CLASS , applicationContextClass )) {
192+ return WebApplicationType .SERVLET ;
193+ }
194+ if (isAssignable (REACTIVE_APPLICATION_CONTEXT_CLASS , applicationContextClass )) {
195+ return WebApplicationType .REACTIVE ;
196+ }
197+ return WebApplicationType .NONE ;
198+ }
199+
200+ private static boolean isAssignable (String target , Class <?> type ) {
201+ try {
202+ return ClassUtils .resolveClassName (target , null ).isAssignableFrom (type );
203+ }
204+ catch (Throwable ex ) {
205+ return false ;
206+ }
207+ }
208+
165209 private boolean isSslEnabled (ApplicationContext context ) {
166210 try {
167211 AbstractReactiveWebServerFactory webServerFactory = context
0 commit comments