Avoid required uri when using WebTestClient w/ base url

This commit makes the `uri` step of the WebTestClient optional, so that
users who have specified a base URL during WebClient config do not need
to provide an empty one (i.e. `url("")`).

Issue: SPR-15695
This commit is contained in:
Arjen Poutsma
2017-07-07 13:38:25 +02:00
parent 3232cb6260
commit 5f2d2b21d9
3 changed files with 91 additions and 74 deletions

View File

@@ -93,38 +93,47 @@ class DefaultWebTestClient implements WebTestClient {
@Override
public UriSpec<RequestHeadersSpec<?>> get() {
return toUriSpec(wc -> wc.method(HttpMethod.GET));
public RequestHeadersUriSpec<?> get() {
return methodInternal(HttpMethod.GET);
}
@Override
public UriSpec<RequestHeadersSpec<?>> head() {
return toUriSpec(wc -> wc.method(HttpMethod.HEAD));
public RequestHeadersUriSpec<?> head() {
return methodInternal(HttpMethod.HEAD);
}
@Override
public UriSpec<RequestBodySpec> post() {
return toUriSpec(wc -> wc.method(HttpMethod.POST));
public RequestBodyUriSpec post() {
return methodInternal(HttpMethod.POST);
}
@Override
public UriSpec<RequestBodySpec> put() {
return toUriSpec(wc -> wc.method(HttpMethod.PUT));
public RequestBodyUriSpec put() {
return methodInternal(HttpMethod.PUT);
}
@Override
public UriSpec<RequestBodySpec> patch() {
return toUriSpec(wc -> wc.method(HttpMethod.PATCH));
public RequestBodyUriSpec patch() {
return methodInternal(HttpMethod.PATCH);
}
@Override
public UriSpec<RequestHeadersSpec<?>> delete() {
return toUriSpec(wc -> wc.method(HttpMethod.DELETE));
public RequestHeadersUriSpec<?> delete() {
return methodInternal(HttpMethod.DELETE);
}
@Override
public UriSpec<RequestHeadersSpec<?>> options() {
return toUriSpec(wc -> wc.method(HttpMethod.OPTIONS));
public RequestHeadersUriSpec<?> options() {
return methodInternal(HttpMethod.OPTIONS);
}
@Override
public RequestBodyUriSpec method(HttpMethod method) {
return methodInternal(method);
}
private RequestBodyUriSpec methodInternal(HttpMethod method) {
return new DefaultRequestBodyUriSpec(this.webClient.method(method));
}
@Override
@@ -132,60 +141,50 @@ class DefaultWebTestClient implements WebTestClient {
return this.builder;
}
private <S extends RequestHeadersSpec<?>> UriSpec<S> toUriSpec(
Function<WebClient, WebClient.UriSpec<WebClient.RequestBodySpec>> function) {
return new DefaultUriSpec<>(function.apply(this.webClient));
}
private class DefaultRequestBodyUriSpec implements RequestBodyUriSpec {
@SuppressWarnings("unchecked")
private class DefaultUriSpec<S extends RequestHeadersSpec<?>> implements UriSpec<S> {
private final WebClient.UriSpec<WebClient.RequestBodySpec> uriSpec;
DefaultUriSpec(WebClient.UriSpec<WebClient.RequestBodySpec> spec) {
this.uriSpec = spec;
}
@Override
public S uri(URI uri) {
return (S) new DefaultRequestBodySpec(this.uriSpec.uri(uri), null);
}
@Override
public S uri(String uriTemplate, Object... uriVariables) {
return (S) new DefaultRequestBodySpec(this.uriSpec.uri(uriTemplate, uriVariables), uriTemplate);
}
@Override
public S uri(String uriTemplate, Map<String, ?> uriVariables) {
return (S) new DefaultRequestBodySpec(this.uriSpec.uri(uriTemplate, uriVariables), uriTemplate);
}
@Override
public S uri(Function<UriBuilder, URI> uriBuilder) {
return (S) new DefaultRequestBodySpec(this.uriSpec.uri(uriBuilder), null);
}
}
private class DefaultRequestBodySpec implements RequestBodySpec {
private final WebClient.RequestBodySpec bodySpec;
private final WebClient.RequestBodyUriSpec bodySpec;
@Nullable
private final String uriTemplate;
private String uriTemplate;
private final String requestId;
DefaultRequestBodySpec(WebClient.RequestBodySpec spec, @Nullable String uriTemplate) {
DefaultRequestBodyUriSpec(WebClient.RequestBodyUriSpec spec) {
this.bodySpec = spec;
this.uriTemplate = uriTemplate;
this.requestId = String.valueOf(requestIndex.incrementAndGet());
this.bodySpec.header(WebTestClient.WEBTESTCLIENT_REQUEST_ID, this.requestId);
}
@Override
public RequestBodySpec uri(String uriTemplate, Object... uriVariables) {
this.bodySpec.uri(uriTemplate, uriVariables);
this.uriTemplate = uriTemplate;
return this;
}
@Override
public RequestBodySpec uri(String uriTemplate, Map<String, ?> uriVariables) {
this.bodySpec.uri(uriTemplate, uriVariables);
this.uriTemplate = uriTemplate;
return this;
}
@Override
public RequestBodySpec uri(Function<UriBuilder, URI> uriFunction) {
this.bodySpec.uri(uriFunction);
this.uriTemplate = null;
return this;
}
@Override
public RequestBodySpec uri(URI uri) {
this.bodySpec.uri(uri);
this.uriTemplate = null;
return this;
}
@Override
public RequestBodySpec header(String headerName, String... headerValues) {
this.bodySpec.header(headerName, headerValues);

View File

@@ -31,6 +31,7 @@ import org.springframework.context.ApplicationContext;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.format.FormatterRegistry;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.client.reactive.ClientHttpRequest;
import org.springframework.http.codec.ServerCodecConfigurer;
@@ -89,43 +90,50 @@ public interface WebTestClient {
* Prepare an HTTP GET request.
* @return a spec for specifying the target URL
*/
UriSpec<RequestHeadersSpec<?>> get();
RequestHeadersUriSpec<?> get();
/**
* Prepare an HTTP HEAD request.
* @return a spec for specifying the target URL
*/
UriSpec<RequestHeadersSpec<?>> head();
RequestHeadersUriSpec<?> head();
/**
* Prepare an HTTP POST request.
* @return a spec for specifying the target URL
*/
UriSpec<RequestBodySpec> post();
RequestBodyUriSpec post();
/**
* Prepare an HTTP PUT request.
* @return a spec for specifying the target URL
*/
UriSpec<RequestBodySpec> put();
RequestBodyUriSpec put();
/**
* Prepare an HTTP PATCH request.
* @return a spec for specifying the target URL
*/
UriSpec<RequestBodySpec> patch();
RequestBodyUriSpec patch();
/**
* Prepare an HTTP DELETE request.
* @return a spec for specifying the target URL
*/
UriSpec<RequestHeadersSpec<?>> delete();
RequestHeadersUriSpec<?> delete();
/**
* Prepare an HTTP OPTIONS request.
* @return a spec for specifying the target URL
*/
UriSpec<RequestHeadersSpec<?>> options();
RequestHeadersUriSpec<?> options();
/**
* Prepare a request for the specified {@code HttpMethod}.
* @return a spec for specifying the target URL
*/
RequestBodyUriSpec method(HttpMethod method);
/**
@@ -152,7 +160,7 @@ public interface WebTestClient {
* detected from an {@link ApplicationContext} such as
* {@code @EnableWebFlux} Java config and annotated controller Spring beans.
* @param applicationContext the context
* @return the {@link WebTestClient} builder
* @return the {@code WebTestClient} builder
* @see org.springframework.web.reactive.config.EnableWebFlux
*/
static MockServerSpec<?> bindToApplicationContext(ApplicationContext applicationContext) {
@@ -162,7 +170,7 @@ public interface WebTestClient {
/**
* Integration testing without a server targeting WebFlux functional endpoints.
* @param routerFunction the RouterFunction to test
* @return the {@link WebTestClient} builder
* @return the {@code WebTestClient} builder
*/
static RouterFunctionSpec bindToRouterFunction(RouterFunction<?> routerFunction) {
return new DefaultRouterFunctionSpec(routerFunction);
@@ -171,7 +179,7 @@ public interface WebTestClient {
/**
* Integration testing with a "mock" server targeting the given WebHandler.
* @param webHandler the handler to test
* @return the {@link WebTestClient} builder
* @return the {@code WebTestClient} builder
*/
static MockServerSpec<?> bindToWebHandler(WebHandler webHandler) {
return new DefaultMockServerSpec(webHandler);
@@ -179,7 +187,7 @@ public interface WebTestClient {
/**
* Complete end-to-end integration tests with actual requests to a running server.
* @return the {@link WebTestClient} builder
* @return the {@code WebTestClient} builder
*/
static Builder bindToServer() {
return new DefaultWebTestClientBuilder();
@@ -580,6 +588,14 @@ public interface WebTestClient {
}
interface RequestHeadersUriSpec<S extends RequestHeadersSpec<S>>
extends UriSpec<S>, RequestHeadersSpec<S> {
}
interface RequestBodyUriSpec extends RequestBodySpec, RequestHeadersUriSpec<RequestBodySpec> {
}
/**
* Spec for declaring expectations on the response.
*/