mirror of
https://github.com/spring-projects/spring-framework
synced 2026-06-08 17:33:33 +00:00
Further alignment of RestTestClient and WebTestClient
See gh-34428
This commit is contained in:
+3
-1
@@ -29,10 +29,12 @@ import org.springframework.util.MultiValueMap;
|
||||
*/
|
||||
public class CookieAssertions extends AbstractCookieAssertions<ExchangeResult, WebTestClient.ResponseSpec> {
|
||||
|
||||
public CookieAssertions(ExchangeResult exchangeResult, WebTestClient.ResponseSpec responseSpec) {
|
||||
|
||||
CookieAssertions(ExchangeResult exchangeResult, WebTestClient.ResponseSpec responseSpec) {
|
||||
super(exchangeResult, responseSpec);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void assertWithDiagnostics(Runnable assertion) {
|
||||
exchangeResult.assertWithDiagnostics(assertion);
|
||||
|
||||
+8
-8
@@ -438,12 +438,12 @@ class DefaultWebTestClient implements WebTestClient {
|
||||
|
||||
|
||||
DefaultResponseSpec(
|
||||
ExchangeResult exchangeResult, ClientResponse response,
|
||||
ExchangeResult result, ClientResponse response,
|
||||
@Nullable JsonEncoderDecoder jsonEncoderDecoder,
|
||||
Consumer<EntityExchangeResult<?>> entityResultConsumer,
|
||||
Duration timeout) {
|
||||
|
||||
this.exchangeResult = exchangeResult;
|
||||
this.exchangeResult = result;
|
||||
this.response = response;
|
||||
this.jsonEncoderDecoder = jsonEncoderDecoder;
|
||||
this.entityResultConsumer = entityResultConsumer;
|
||||
@@ -468,15 +468,15 @@ class DefaultWebTestClient implements WebTestClient {
|
||||
@Override
|
||||
public <B> BodySpec<B, ?> expectBody(Class<B> bodyType) {
|
||||
B body = this.response.bodyToMono(bodyType).block(this.timeout);
|
||||
EntityExchangeResult<B> entityResult = initEntityExchangeResult(body);
|
||||
return new DefaultBodySpec<>(entityResult);
|
||||
EntityExchangeResult<B> result = initEntityExchangeResult(body);
|
||||
return new DefaultBodySpec<>(result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <B> BodySpec<B, ?> expectBody(ParameterizedTypeReference<B> bodyType) {
|
||||
B body = this.response.bodyToMono(bodyType).block(this.timeout);
|
||||
EntityExchangeResult<B> entityResult = initEntityExchangeResult(body);
|
||||
return new DefaultBodySpec<>(entityResult);
|
||||
EntityExchangeResult<B> result = initEntityExchangeResult(body);
|
||||
return new DefaultBodySpec<>(result);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -500,8 +500,8 @@ class DefaultWebTestClient implements WebTestClient {
|
||||
public BodyContentSpec expectBody() {
|
||||
ByteArrayResource resource = this.response.bodyToMono(ByteArrayResource.class).block(this.timeout);
|
||||
byte[] body = (resource != null ? resource.getByteArray() : null);
|
||||
EntityExchangeResult<byte[]> entityResult = initEntityExchangeResult(body);
|
||||
return new DefaultBodyContentSpec(entityResult, this.jsonEncoderDecoder);
|
||||
EntityExchangeResult<byte[]> result = initEntityExchangeResult(body);
|
||||
return new DefaultBodyContentSpec(result, this.jsonEncoderDecoder);
|
||||
}
|
||||
|
||||
private <B> EntityExchangeResult<B> initEntityExchangeResult(@Nullable B body) {
|
||||
|
||||
+2
@@ -31,10 +31,12 @@ import org.springframework.test.web.support.AbstractHeaderAssertions;
|
||||
*/
|
||||
public class HeaderAssertions extends AbstractHeaderAssertions<ExchangeResult, WebTestClient.ResponseSpec> {
|
||||
|
||||
|
||||
HeaderAssertions(ExchangeResult result, WebTestClient.ResponseSpec spec) {
|
||||
super(result, spec);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void assertWithDiagnostics(Runnable assertion) {
|
||||
exchangeResult.assertWithDiagnostics(assertion);
|
||||
|
||||
+4
-1
@@ -34,8 +34,11 @@ import org.springframework.test.web.support.AbstractJsonPathAssertions;
|
||||
*/
|
||||
public class JsonPathAssertions extends AbstractJsonPathAssertions<WebTestClient.BodyContentSpec> {
|
||||
|
||||
JsonPathAssertions(WebTestClient.BodyContentSpec spec, String content, String expression,
|
||||
|
||||
JsonPathAssertions(
|
||||
WebTestClient.BodyContentSpec spec, String content, String expression,
|
||||
@Nullable Configuration configuration) {
|
||||
|
||||
super(spec, content, expression, configuration);
|
||||
}
|
||||
}
|
||||
|
||||
+2
@@ -29,10 +29,12 @@ import org.springframework.test.web.support.AbstractStatusAssertions;
|
||||
*/
|
||||
public class StatusAssertions extends AbstractStatusAssertions<ExchangeResult, WebTestClient.ResponseSpec> {
|
||||
|
||||
|
||||
StatusAssertions(ExchangeResult result, WebTestClient.ResponseSpec spec) {
|
||||
super(result, spec);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void assertWithDiagnostics(Runnable assertion) {
|
||||
exchangeResult.assertWithDiagnostics(assertion);
|
||||
|
||||
+20
-30
@@ -73,7 +73,7 @@ import org.springframework.web.util.UriBuilderFactory;
|
||||
* Client for testing web servers that uses {@link WebClient} internally to
|
||||
* perform requests while also providing a fluent API to verify responses.
|
||||
* This client can connect to any server over HTTP, or to a WebFlux application
|
||||
* via mock request and response objects.
|
||||
* with a mock request and response.
|
||||
*
|
||||
* <p>Use one of the bindToXxx methods to create an instance. For example:
|
||||
* <ul>
|
||||
@@ -89,9 +89,6 @@ import org.springframework.web.util.UriBuilderFactory;
|
||||
* @author Sam Brannen
|
||||
* @author Michał Rowicki
|
||||
* @since 5.0
|
||||
* @see StatusAssertions
|
||||
* @see HeaderAssertions
|
||||
* @see JsonPathAssertions
|
||||
*/
|
||||
public interface WebTestClient {
|
||||
|
||||
@@ -172,12 +169,10 @@ public interface WebTestClient {
|
||||
|
||||
|
||||
/**
|
||||
* Use this server setup to test one {@code @Controller} at a time.
|
||||
* This option loads the default configuration of
|
||||
* {@link org.springframework.web.reactive.config.EnableWebFlux @EnableWebFlux}.
|
||||
* There are builder methods to customize the Java config. The resulting
|
||||
* WebFlux application will be tested without an HTTP server using a mock
|
||||
* request and response.
|
||||
* Begin creating a {@link WebTestClient} with a mock server setup that
|
||||
* tests one {@code @Controller} at a time with
|
||||
* {@link org.springframework.web.reactive.config.EnableWebFlux @EnableWebFlux}
|
||||
* equivalent configuration.
|
||||
* @param controllers one or more controller instances to test
|
||||
* (specified {@code Class} will be turned into instance)
|
||||
* @return chained API to customize server and client config; use
|
||||
@@ -188,10 +183,10 @@ public interface WebTestClient {
|
||||
}
|
||||
|
||||
/**
|
||||
* Use this option to set up a server from a {@link RouterFunction}.
|
||||
* Internally the provided configuration is passed to
|
||||
* {@code RouterFunctions#toWebHandler}. The resulting WebFlux application
|
||||
* will be tested without an HTTP server using a mock request and response.
|
||||
* Begin creating a {@link WebTestClient} with a mock server setup that
|
||||
* tests one {@code RouterFunction} at a time with
|
||||
* {@link org.springframework.web.reactive.config.EnableWebFlux @EnableWebFlux}
|
||||
* equivalent configuration.
|
||||
* @param routerFunction the RouterFunction to test
|
||||
* @return chained API to customize server and client config; use
|
||||
* {@link MockServerSpec#configureClient()} to transition to client config
|
||||
@@ -229,8 +224,7 @@ public interface WebTestClient {
|
||||
}
|
||||
|
||||
/**
|
||||
* This server setup option allows you to connect to a live server through
|
||||
* a Reactor Netty client connector.
|
||||
* This server setup option allows you to connect to a live server.
|
||||
* <p><pre class="code">
|
||||
* WebTestClient client = WebTestClient.bindToServer()
|
||||
* .baseUrl("http://localhost:8080")
|
||||
@@ -389,17 +383,12 @@ public interface WebTestClient {
|
||||
|
||||
|
||||
/**
|
||||
* Steps for customizing the {@link WebClient} used to test with,
|
||||
* internally delegating to a
|
||||
* {@link org.springframework.web.reactive.function.client.WebClient.Builder
|
||||
* WebClient.Builder}.
|
||||
* Steps to customize the underlying {@link WebClient} via {@link WebClient.Builder}.
|
||||
*/
|
||||
interface Builder {
|
||||
|
||||
/**
|
||||
* Configure a base URI as described in
|
||||
* {@link org.springframework.web.reactive.function.client.WebClient#create(String)
|
||||
* WebClient.create(String)}.
|
||||
* Configure a base URI as described in {@link WebClient#create(String)}.
|
||||
*/
|
||||
Builder baseUrl(String baseUrl);
|
||||
|
||||
@@ -428,7 +417,7 @@ public interface WebTestClient {
|
||||
Builder defaultHeaders(Consumer<HttpHeaders> headersConsumer);
|
||||
|
||||
/**
|
||||
* Add the given header to all requests that haven't added it.
|
||||
* Add the given cookie to all requests that haven't already added it.
|
||||
* @param cookieName the cookie name
|
||||
* @param cookieValues the cookie values
|
||||
*/
|
||||
@@ -718,6 +707,7 @@ public interface WebTestClient {
|
||||
* Specification for providing body of a request.
|
||||
*/
|
||||
interface RequestBodySpec extends RequestHeadersSpec<RequestBodySpec> {
|
||||
|
||||
/**
|
||||
* Set the length of the body in bytes, as specified by the
|
||||
* {@code Content-Length} header.
|
||||
@@ -738,7 +728,7 @@ public interface WebTestClient {
|
||||
|
||||
/**
|
||||
* Set the body to the given {@code Object} value. This method invokes the
|
||||
* {@link org.springframework.web.reactive.function.client.WebClient.RequestBodySpec#bodyValue(Object)
|
||||
* {@link WebClient.RequestBodySpec#bodyValue(Object)
|
||||
* bodyValue} method on the underlying {@code WebClient}.
|
||||
* @param body the value to write to the request body
|
||||
* @return spec for further declaration of the request
|
||||
@@ -773,7 +763,7 @@ public interface WebTestClient {
|
||||
|
||||
/**
|
||||
* Set the body from the given producer. This method invokes the
|
||||
* {@link org.springframework.web.reactive.function.client.WebClient.RequestBodySpec#body(Object, Class)
|
||||
* {@link WebClient.RequestBodySpec#body(Object, Class)
|
||||
* body(Object, Class)} method on the underlying {@code WebClient}.
|
||||
* @param producer the producer to write to the request. This must be a
|
||||
* {@link Publisher} or another producer adaptable to a
|
||||
@@ -786,7 +776,7 @@ public interface WebTestClient {
|
||||
|
||||
/**
|
||||
* Set the body from the given producer. This method invokes the
|
||||
* {@link org.springframework.web.reactive.function.client.WebClient.RequestBodySpec#body(Object, ParameterizedTypeReference)
|
||||
* {@link WebClient.RequestBodySpec#body(Object, ParameterizedTypeReference)
|
||||
* body(Object, ParameterizedTypeReference)} method on the underlying {@code WebClient}.
|
||||
* @param producer the producer to write to the request. This must be a
|
||||
* {@link Publisher} or another producer adaptable to a
|
||||
@@ -800,7 +790,7 @@ public interface WebTestClient {
|
||||
/**
|
||||
* Set the body of the request to the given {@code BodyInserter}.
|
||||
* This method invokes the
|
||||
* {@link org.springframework.web.reactive.function.client.WebClient.RequestBodySpec#body(BodyInserter)
|
||||
* {@link WebClient.RequestBodySpec#body(BodyInserter)
|
||||
* body(BodyInserter)} method on the underlying {@code WebClient}.
|
||||
* @param inserter the body inserter to use
|
||||
* @return spec for further declaration of the request
|
||||
@@ -908,8 +898,8 @@ public interface WebTestClient {
|
||||
BodyContentSpec expectBody();
|
||||
|
||||
/**
|
||||
* Exit the chained flow in order to consume the response body
|
||||
* externally, for example, via {@link reactor.test.StepVerifier}.
|
||||
* Exit the chained flow in order to consume the response body externally,
|
||||
* for example, via {@link reactor.test.StepVerifier}.
|
||||
* <p>Note that when {@code Void.class} is passed in, the response body
|
||||
* is consumed and released. If no content is expected, then consider
|
||||
* using {@code .expectBody().isEmpty()} instead which asserts that
|
||||
|
||||
+3
-1
@@ -28,10 +28,12 @@ import org.springframework.util.MultiValueMap;
|
||||
*/
|
||||
public class CookieAssertions extends AbstractCookieAssertions<ExchangeResult, RestTestClient.ResponseSpec> {
|
||||
|
||||
public CookieAssertions(ExchangeResult exchangeResult, RestTestClient.ResponseSpec responseSpec) {
|
||||
|
||||
CookieAssertions(ExchangeResult exchangeResult, RestTestClient.ResponseSpec responseSpec) {
|
||||
super(exchangeResult, responseSpec);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void assertWithDiagnostics(Runnable assertion) {
|
||||
exchangeResult.assertWithDiagnostics(assertion);
|
||||
|
||||
+53
-48
@@ -21,7 +21,6 @@ import java.nio.charset.Charset;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
import java.util.function.Consumer;
|
||||
@@ -59,12 +58,9 @@ class DefaultRestTestClient implements RestTestClient {
|
||||
|
||||
private final AtomicLong requestIndex = new AtomicLong();
|
||||
|
||||
private final RestClient.Builder restClientBuilder;
|
||||
|
||||
|
||||
DefaultRestTestClient(RestClient.Builder restClientBuilder) {
|
||||
this.restClient = restClientBuilder.build();
|
||||
this.restClientBuilder = restClientBuilder;
|
||||
DefaultRestTestClient(RestClient.Builder builder) {
|
||||
this.restClient = builder.build();
|
||||
}
|
||||
|
||||
|
||||
@@ -104,8 +100,8 @@ class DefaultRestTestClient implements RestTestClient {
|
||||
}
|
||||
|
||||
@Override
|
||||
public RequestBodyUriSpec method(HttpMethod method) {
|
||||
return methodInternal(method);
|
||||
public RequestBodyUriSpec method(HttpMethod httpMethod) {
|
||||
return methodInternal(httpMethod);
|
||||
}
|
||||
|
||||
private RequestBodyUriSpec methodInternal(HttpMethod httpMethod) {
|
||||
@@ -114,7 +110,7 @@ class DefaultRestTestClient implements RestTestClient {
|
||||
|
||||
@Override
|
||||
public <B extends Builder<B>> Builder<B> mutate() {
|
||||
return new DefaultRestTestClientBuilder<>(this.restClientBuilder);
|
||||
return new DefaultRestTestClientBuilder<>(this.restClient.mutate());
|
||||
}
|
||||
|
||||
|
||||
@@ -122,103 +118,105 @@ class DefaultRestTestClient implements RestTestClient {
|
||||
|
||||
private final RestClient.RequestBodyUriSpec requestHeadersUriSpec;
|
||||
|
||||
private RestClient.RequestBodySpec requestBodySpec;
|
||||
|
||||
private final String requestId;
|
||||
|
||||
DefaultRequestBodyUriSpec(RestClient.RequestBodyUriSpec spec) {
|
||||
this.requestHeadersUriSpec = spec;
|
||||
this.requestBodySpec = spec;
|
||||
this.requestId = String.valueOf(requestIndex.incrementAndGet());
|
||||
String requestId = String.valueOf(requestIndex.incrementAndGet());
|
||||
this.requestHeadersUriSpec.header(RESTTESTCLIENT_REQUEST_ID, requestId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RequestBodySpec uri(String uriTemplate, Object... uriVariables) {
|
||||
this.requestBodySpec = this.requestHeadersUriSpec.uri(uriTemplate, uriVariables);
|
||||
public RequestBodySpec uri(String uriTemplate, @Nullable Object... uriVariables) {
|
||||
this.requestHeadersUriSpec.uri(uriTemplate, uriVariables);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RequestBodySpec uri(String uri, Map<String, ?> uriVariables) {
|
||||
this.requestBodySpec = this.requestHeadersUriSpec.uri(uri, uriVariables);
|
||||
this.requestHeadersUriSpec.uri(uri, uriVariables);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RequestBodySpec uri(Function<UriBuilder, URI> uriFunction) {
|
||||
this.requestBodySpec = this.requestHeadersUriSpec.uri(uriFunction);
|
||||
this.requestHeadersUriSpec.uri(uriFunction);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RequestBodySpec uri(URI uri) {
|
||||
this.requestBodySpec = this.requestHeadersUriSpec.uri(uri);
|
||||
this.requestHeadersUriSpec.uri(uri);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RequestBodySpec header(String headerName, String... headerValues) {
|
||||
this.requestBodySpec = this.requestHeadersUriSpec.header(headerName, headerValues);
|
||||
this.requestHeadersUriSpec.header(headerName, headerValues);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RequestBodySpec headers(Consumer<HttpHeaders> headersConsumer) {
|
||||
this.requestBodySpec = this.requestHeadersUriSpec.headers(headersConsumer);
|
||||
this.requestHeadersUriSpec.headers(headersConsumer);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RequestBodySpec accept(MediaType... acceptableMediaTypes) {
|
||||
this.requestBodySpec = this.requestHeadersUriSpec.accept(acceptableMediaTypes);
|
||||
this.requestHeadersUriSpec.accept(acceptableMediaTypes);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RequestBodySpec acceptCharset(Charset... acceptableCharsets) {
|
||||
this.requestBodySpec = this.requestHeadersUriSpec.acceptCharset(acceptableCharsets);
|
||||
this.requestHeadersUriSpec.acceptCharset(acceptableCharsets);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RequestBodySpec contentType(MediaType contentType) {
|
||||
this.requestBodySpec = this.requestHeadersUriSpec.contentType(contentType);
|
||||
this.requestHeadersUriSpec.contentType(contentType);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RequestBodySpec contentLength(long contentLength) {
|
||||
this.requestHeadersUriSpec.contentLength(contentLength);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RequestBodySpec cookie(String name, String value) {
|
||||
this.requestBodySpec = this.requestHeadersUriSpec.cookie(name, value);
|
||||
this.requestHeadersUriSpec.cookie(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RequestBodySpec cookies(Consumer<MultiValueMap<String, String>> cookiesConsumer) {
|
||||
this.requestBodySpec = this.requestHeadersUriSpec.cookies(cookiesConsumer);
|
||||
this.requestHeadersUriSpec.cookies(cookiesConsumer);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RequestBodySpec ifModifiedSince(ZonedDateTime ifModifiedSince) {
|
||||
this.requestBodySpec = this.requestHeadersUriSpec.ifModifiedSince(ifModifiedSince);
|
||||
this.requestHeadersUriSpec.ifModifiedSince(ifModifiedSince);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RequestBodySpec ifNoneMatch(String... ifNoneMatches) {
|
||||
this.requestBodySpec = this.requestHeadersUriSpec.ifNoneMatch(ifNoneMatches);
|
||||
this.requestHeadersUriSpec.ifNoneMatch(ifNoneMatches);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RequestBodySpec attribute(String name, Object value) {
|
||||
this.requestBodySpec = this.requestHeadersUriSpec.attribute(name, value);
|
||||
this.requestHeadersUriSpec.attribute(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RequestBodySpec attributes(Consumer<Map<String, Object>> attributesConsumer) {
|
||||
this.requestBodySpec = this.requestHeadersUriSpec.attributes(attributesConsumer);
|
||||
this.requestHeadersUriSpec.attributes(attributesConsumer);
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -230,11 +228,9 @@ class DefaultRestTestClient implements RestTestClient {
|
||||
|
||||
@Override
|
||||
public ResponseSpec exchange() {
|
||||
this.requestBodySpec = this.requestBodySpec.header(RESTTESTCLIENT_REQUEST_ID, this.requestId);
|
||||
ExchangeResult exchangeResult = this.requestBodySpec.exchange(
|
||||
(clientRequest, clientResponse) -> new ExchangeResult(clientResponse),
|
||||
false);
|
||||
return new DefaultResponseSpec(Objects.requireNonNull(exchangeResult));
|
||||
return new DefaultResponseSpec(
|
||||
this.requestHeadersUriSpec.exchangeForRequiredValue(
|
||||
(request, response) -> new ExchangeResult(response), false));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -243,8 +239,8 @@ class DefaultRestTestClient implements RestTestClient {
|
||||
|
||||
private final ExchangeResult exchangeResult;
|
||||
|
||||
DefaultResponseSpec(ExchangeResult exchangeResult) {
|
||||
this.exchangeResult = exchangeResult;
|
||||
DefaultResponseSpec(ExchangeResult result) {
|
||||
this.exchangeResult = result;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -265,19 +261,22 @@ class DefaultRestTestClient implements RestTestClient {
|
||||
@Override
|
||||
public <B> BodySpec<B, ?> expectBody(Class<B> bodyType) {
|
||||
B body = this.exchangeResult.getBody(bodyType);
|
||||
return new DefaultBodySpec<>(new EntityExchangeResult<>(this.exchangeResult, body));
|
||||
EntityExchangeResult<B> result = new EntityExchangeResult<>(this.exchangeResult, body);
|
||||
return new DefaultBodySpec<>(result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <B> BodySpec<B, ?> expectBody(ParameterizedTypeReference<B> bodyType) {
|
||||
B body = this.exchangeResult.getBody(bodyType);
|
||||
return new DefaultBodySpec<>(new EntityExchangeResult<>(this.exchangeResult, body));
|
||||
EntityExchangeResult<B> result = new EntityExchangeResult<>(this.exchangeResult, body);
|
||||
return new DefaultBodySpec<>(result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BodyContentSpec expectBody() {
|
||||
byte[] body = this.exchangeResult.getBody(byte[].class);
|
||||
return new DefaultBodyContentSpec( new EntityExchangeResult<>(this.exchangeResult, body));
|
||||
EntityExchangeResult<byte[]> result = new EntityExchangeResult<>(this.exchangeResult, body);
|
||||
return new DefaultBodyContentSpec(result);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -318,20 +317,26 @@ class DefaultRestTestClient implements RestTestClient {
|
||||
|
||||
private final EntityExchangeResult<B> result;
|
||||
|
||||
DefaultBodySpec(@Nullable EntityExchangeResult<B> result) {
|
||||
this.result = Objects.requireNonNull(result, "exchangeResult must be non-null");
|
||||
DefaultBodySpec(EntityExchangeResult<B> result) {
|
||||
this.result = result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends S> T isEqualTo(B expected) {
|
||||
public <T extends S> T isEqualTo(@Nullable B expected) {
|
||||
this.result.assertWithDiagnostics(() ->
|
||||
AssertionErrors.assertEquals("Response body", expected, this.result.getResponseBody()));
|
||||
return self();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends S> T value(Matcher<? super @Nullable B> matcher) {
|
||||
this.result.assertWithDiagnostics(() -> MatcherAssert.assertThat(this.result.getResponseBody(), matcher));
|
||||
return self();
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("NullAway") // https://github.com/uber/NullAway/issues/1129
|
||||
public <T extends S, R> T value(Function<B, R> bodyMapper, Matcher<? super R> matcher) {
|
||||
public <T extends S, R> T value(Function<@Nullable B, @Nullable R> bodyMapper, Matcher<? super @Nullable R> matcher) {
|
||||
this.result.assertWithDiagnostics(() -> {
|
||||
B body = this.result.getResponseBody();
|
||||
MatcherAssert.assertThat(bodyMapper.apply(body), matcher);
|
||||
@@ -340,7 +345,8 @@ class DefaultRestTestClient implements RestTestClient {
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends S> T value(Consumer<B> consumer) {
|
||||
@SuppressWarnings("NullAway") // https://github.com/uber/NullAway/issues/1129
|
||||
public <T extends S> T value(Consumer<@Nullable B> consumer) {
|
||||
this.result.assertWithDiagnostics(() -> consumer.accept(this.result.getResponseBody()));
|
||||
return self();
|
||||
}
|
||||
@@ -374,8 +380,7 @@ class DefaultRestTestClient implements RestTestClient {
|
||||
@Override
|
||||
public EntityExchangeResult<Void> isEmpty() {
|
||||
this.result.assertWithDiagnostics(() ->
|
||||
AssertionErrors.assertTrue("Expected empty body",
|
||||
this.result.getBody(byte[].class) == null));
|
||||
AssertionErrors.assertTrue("Expected empty body", this.result.getBody(byte[].class) == null));
|
||||
return new EntityExchangeResult<>(this.result, null);
|
||||
}
|
||||
|
||||
|
||||
+29
-16
@@ -18,12 +18,14 @@ package org.springframework.test.web.servlet.client;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.client.ClientHttpRequestFactory;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.MockMvcBuilder;
|
||||
import org.springframework.test.web.servlet.client.RestTestClient.MockMvcSetupBuilder;
|
||||
import org.springframework.test.web.servlet.client.RestTestClient.RouterFunctionSetupBuilder;
|
||||
import org.springframework.test.web.servlet.client.RestTestClient.StandaloneSetupBuilder;
|
||||
import org.springframework.test.web.servlet.client.RestTestClient.WebAppContextSetupBuilder;
|
||||
import org.springframework.test.web.servlet.setup.DefaultMockMvcBuilder;
|
||||
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
|
||||
import org.springframework.test.web.servlet.setup.RouterFunctionMockMvcBuilder;
|
||||
@@ -39,8 +41,8 @@ import org.springframework.web.util.UriBuilderFactory;
|
||||
*
|
||||
* @author Rob Worsnop
|
||||
* @author Rossen Stoyanchev
|
||||
* @param <B> the type of the builder
|
||||
* @since 7.0
|
||||
* @param <B> the type of the builder
|
||||
*/
|
||||
class DefaultRestTestClientBuilder<B extends RestTestClient.Builder<B>> implements RestTestClient.Builder<B> {
|
||||
|
||||
@@ -92,12 +94,6 @@ class DefaultRestTestClientBuilder<B extends RestTestClient.Builder<B>> implemen
|
||||
return self();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends B> T apply(Consumer<RestTestClient.Builder<B>> builderConsumer) {
|
||||
builderConsumer.accept(this);
|
||||
return self();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
protected <T extends B> T self() {
|
||||
return (T) this;
|
||||
@@ -113,8 +109,13 @@ class DefaultRestTestClientBuilder<B extends RestTestClient.Builder<B>> implemen
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Base class for implementations for {@link MockMvcSetupBuilder}.
|
||||
* @param <S> the "self" type of the builder
|
||||
* @param <M> the type of {@link MockMvc} builder
|
||||
*/
|
||||
static class AbstractMockMvcSetupBuilder<S extends RestTestClient.Builder<S>, M extends MockMvcBuilder>
|
||||
extends DefaultRestTestClientBuilder<S> implements RestTestClient.MockMvcSetupBuilder<S, M> {
|
||||
extends DefaultRestTestClientBuilder<S> implements MockMvcSetupBuilder<S, M> {
|
||||
|
||||
private final M mockMvcBuilder;
|
||||
|
||||
@@ -136,8 +137,12 @@ class DefaultRestTestClientBuilder<B extends RestTestClient.Builder<B>> implemen
|
||||
}
|
||||
|
||||
|
||||
static class DefaultStandaloneSetupBuilder extends AbstractMockMvcSetupBuilder<RestTestClient.StandaloneSetupBuilder, StandaloneMockMvcBuilder>
|
||||
implements RestTestClient.StandaloneSetupBuilder {
|
||||
/**
|
||||
* Default implementation of {@link StandaloneSetupBuilder}.
|
||||
*/
|
||||
static class DefaultStandaloneSetupBuilder
|
||||
extends AbstractMockMvcSetupBuilder<StandaloneSetupBuilder, StandaloneMockMvcBuilder>
|
||||
implements StandaloneSetupBuilder {
|
||||
|
||||
DefaultStandaloneSetupBuilder(Object... controllers) {
|
||||
super(MockMvcBuilders.standaloneSetup(controllers));
|
||||
@@ -145,8 +150,12 @@ class DefaultRestTestClientBuilder<B extends RestTestClient.Builder<B>> implemen
|
||||
}
|
||||
|
||||
|
||||
static class DefaultRouterFunctionSetupBuilder extends AbstractMockMvcSetupBuilder<RestTestClient.RouterFunctionSetupBuilder, RouterFunctionMockMvcBuilder>
|
||||
implements RestTestClient.RouterFunctionSetupBuilder {
|
||||
/**
|
||||
* Default implementation of {@link RouterFunctionSetupBuilder}.
|
||||
*/
|
||||
static class DefaultRouterFunctionSetupBuilder
|
||||
extends AbstractMockMvcSetupBuilder<RouterFunctionSetupBuilder, RouterFunctionMockMvcBuilder>
|
||||
implements RouterFunctionSetupBuilder {
|
||||
|
||||
DefaultRouterFunctionSetupBuilder(RouterFunction<?>... routerFunctions) {
|
||||
super(MockMvcBuilders.routerFunctions(routerFunctions));
|
||||
@@ -155,8 +164,12 @@ class DefaultRestTestClientBuilder<B extends RestTestClient.Builder<B>> implemen
|
||||
}
|
||||
|
||||
|
||||
static class DefaultWebAppContextSetupBuilder extends AbstractMockMvcSetupBuilder<RestTestClient.WebAppContextSetupBuilder, DefaultMockMvcBuilder>
|
||||
implements RestTestClient.WebAppContextSetupBuilder {
|
||||
/**
|
||||
* Default implementation of {@link WebAppContextSetupBuilder}.
|
||||
*/
|
||||
static class DefaultWebAppContextSetupBuilder
|
||||
extends AbstractMockMvcSetupBuilder<WebAppContextSetupBuilder, DefaultMockMvcBuilder>
|
||||
implements WebAppContextSetupBuilder {
|
||||
|
||||
DefaultWebAppContextSetupBuilder(WebApplicationContext context) {
|
||||
super(MockMvcBuilders.webAppContextSetup(context));
|
||||
|
||||
+48
-34
@@ -19,7 +19,6 @@ package org.springframework.test.web.servlet.client;
|
||||
import java.io.IOException;
|
||||
import java.net.HttpCookie;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
@@ -32,6 +31,7 @@ import org.springframework.core.ParameterizedTypeReference;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpStatusCode;
|
||||
import org.springframework.http.ResponseCookie;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.web.client.RestClient.RequestHeadersSpec.ConvertibleClientHttpResponse;
|
||||
@@ -41,21 +41,28 @@ import org.springframework.web.client.RestClient.RequestHeadersSpec.ConvertibleC
|
||||
* {@link RestTestClient}.
|
||||
*
|
||||
* @author Rob Worsnop
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 7.0
|
||||
*/
|
||||
public class ExchangeResult {
|
||||
|
||||
private static final Pattern SAME_SITE_PATTERN = Pattern.compile("(?i).*SameSite=(Strict|Lax|None).*");
|
||||
|
||||
private static final Pattern PARTITIONED_PATTERN = Pattern.compile("(?i).*;\\s*Partitioned(\\s*;.*|\\s*)$");
|
||||
|
||||
|
||||
private static final Log logger = LogFactory.getLog(ExchangeResult.class);
|
||||
|
||||
/** Ensure single logging; for example, for expectAll. */
|
||||
private boolean diagnosticsLogged;
|
||||
|
||||
private final ConvertibleClientHttpResponse clientResponse;
|
||||
|
||||
ExchangeResult(@Nullable ConvertibleClientHttpResponse clientResponse) {
|
||||
this.clientResponse = Objects.requireNonNull(clientResponse, "clientResponse must be non-null");
|
||||
/** Ensure single logging; for example, for expectAll. */
|
||||
private boolean diagnosticsLogged;
|
||||
|
||||
|
||||
ExchangeResult(@Nullable ConvertibleClientHttpResponse response) {
|
||||
Assert.notNull(response, "Response must not be null");
|
||||
this.clientResponse = response;
|
||||
}
|
||||
|
||||
ExchangeResult(ExchangeResult result) {
|
||||
@@ -63,6 +70,10 @@ public class ExchangeResult {
|
||||
this.diagnosticsLogged = result.diagnosticsLogged;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the HTTP status code as an {@link HttpStatusCode} value.
|
||||
*/
|
||||
public HttpStatusCode getStatus() {
|
||||
try {
|
||||
return this.clientResponse.getStatusCode();
|
||||
@@ -72,39 +83,13 @@ public class ExchangeResult {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the response headers received from the server.
|
||||
*/
|
||||
public HttpHeaders getResponseHeaders() {
|
||||
return this.clientResponse.getHeaders();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public <T> T getBody(Class<T> bodyType) {
|
||||
return this.clientResponse.bodyTo(bodyType);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public <T> T getBody(ParameterizedTypeReference<T> bodyType) {
|
||||
return this.clientResponse.bodyTo(bodyType);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Execute the given Runnable, catch any {@link AssertionError}, log details
|
||||
* about the request and response at ERROR level under the class log
|
||||
* category, and after that re-throw the error.
|
||||
*/
|
||||
public void assertWithDiagnostics(Runnable assertion) {
|
||||
try {
|
||||
assertion.run();
|
||||
}
|
||||
catch (AssertionError ex) {
|
||||
if (!this.diagnosticsLogged && logger.isErrorEnabled()) {
|
||||
this.diagnosticsLogged = true;
|
||||
logger.error("Request details for assertion failure:\n" + this);
|
||||
}
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return response cookies received from the server.
|
||||
*/
|
||||
@@ -132,4 +117,33 @@ public class ExchangeResult {
|
||||
.partitioned(partitioned)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public <T> T getBody(Class<T> bodyType) {
|
||||
return this.clientResponse.bodyTo(bodyType);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public <T> T getBody(ParameterizedTypeReference<T> bodyType) {
|
||||
return this.clientResponse.bodyTo(bodyType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the given Runnable, catch any {@link AssertionError}, log details
|
||||
* about the request and response at ERROR level under the class log
|
||||
* category, and after that re-throw the error.
|
||||
*/
|
||||
public void assertWithDiagnostics(Runnable assertion) {
|
||||
try {
|
||||
assertion.run();
|
||||
}
|
||||
catch (AssertionError ex) {
|
||||
if (!this.diagnosticsLogged && logger.isErrorEnabled()) {
|
||||
this.diagnosticsLogged = true;
|
||||
logger.error("Request details for assertion failure:\n" + this);
|
||||
}
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+1
-1
@@ -29,7 +29,7 @@ import org.springframework.test.web.support.AbstractHeaderAssertions;
|
||||
public class HeaderAssertions extends AbstractHeaderAssertions<ExchangeResult, RestTestClient.ResponseSpec> {
|
||||
|
||||
|
||||
public HeaderAssertions(ExchangeResult exchangeResult, RestTestClient.ResponseSpec responseSpec) {
|
||||
HeaderAssertions(ExchangeResult exchangeResult, RestTestClient.ResponseSpec responseSpec) {
|
||||
super(exchangeResult, responseSpec);
|
||||
}
|
||||
|
||||
|
||||
+7
-1
@@ -26,13 +26,19 @@ import org.springframework.test.web.support.AbstractJsonPathAssertions;
|
||||
* <a href="https://github.com/jayway/JsonPath">JsonPath</a> assertions.
|
||||
*
|
||||
* @author Rob Worsnop
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 7.0
|
||||
* @see <a href="https://github.com/jayway/JsonPath">https://github.com/jayway/JsonPath</a>
|
||||
* @see JsonPathExpectationsHelper
|
||||
*/
|
||||
public class JsonPathAssertions extends AbstractJsonPathAssertions<RestTestClient.BodyContentSpec> {
|
||||
|
||||
JsonPathAssertions(RestTestClient.BodyContentSpec spec, String content, String expression, @Nullable Configuration configuration) {
|
||||
|
||||
JsonPathAssertions(
|
||||
RestTestClient.BodyContentSpec spec, String content, String expression,
|
||||
@Nullable Configuration configuration) {
|
||||
|
||||
super(spec, content, expression, configuration);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+79
-51
@@ -37,6 +37,7 @@ import org.springframework.test.json.JsonComparison;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.MockMvcBuilder;
|
||||
import org.springframework.test.web.servlet.setup.DefaultMockMvcBuilder;
|
||||
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
|
||||
import org.springframework.test.web.servlet.setup.RouterFunctionMockMvcBuilder;
|
||||
import org.springframework.test.web.servlet.setup.StandaloneMockMvcBuilder;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
@@ -47,7 +48,19 @@ import org.springframework.web.util.UriBuilder;
|
||||
import org.springframework.web.util.UriBuilderFactory;
|
||||
|
||||
/**
|
||||
* Client for testing web servers.
|
||||
* Client for testing web servers that uses {@link RestClient} internally to
|
||||
* perform requests while also providing a fluent API to verify responses.
|
||||
* This client can connect to any server over HTTP or to a {@link MockMvc} server
|
||||
* with a mock request and response.
|
||||
*
|
||||
* <p>Use one of the bindToXxx methods to create an instance. For example:
|
||||
* <ul>
|
||||
* <li>{@link #bindToController(Object...)}
|
||||
* <li>{@link #bindToRouterFunction(RouterFunction[])}
|
||||
* <li>{@link #bindToApplicationContext(WebApplicationContext)}
|
||||
* <li>{@link #bindToServer()}
|
||||
* <li>...
|
||||
* </ul>
|
||||
*
|
||||
* @author Rob Worsnop
|
||||
* @author Rossen Stoyanchev
|
||||
@@ -121,34 +134,24 @@ public interface RestTestClient {
|
||||
|
||||
|
||||
/**
|
||||
* Begin creating a {@link RestTestClient} by providing the {@code @Controller}
|
||||
* instance(s) to handle requests with.
|
||||
* <p>Internally this is delegated to and equivalent to using
|
||||
* {@link org.springframework.test.web.servlet.setup.MockMvcBuilders#standaloneSetup(Object...)}
|
||||
* to initialize {@link MockMvc}.
|
||||
* Begin creating a {@link RestTestClient} with a {@link MockMvcBuilders#standaloneSetup
|
||||
* Standalone MockMvc setup}.
|
||||
*/
|
||||
static StandaloneSetupBuilder bindToController(Object... controllers) {
|
||||
return new DefaultRestTestClientBuilder.DefaultStandaloneSetupBuilder(controllers);
|
||||
}
|
||||
|
||||
/**
|
||||
* Begin creating a {@link RestTestClient} by providing the {@link RouterFunction}
|
||||
* instance(s) to handle requests with.
|
||||
* <p>Internally this is delegated to and equivalent to using
|
||||
* {@link org.springframework.test.web.servlet.setup.MockMvcBuilders#routerFunctions(RouterFunction[])}
|
||||
* to initialize {@link MockMvc}.
|
||||
* Begin creating a {@link RestTestClient} with a {@link MockMvcBuilders#routerFunctions}
|
||||
* RouterFunction's MockMvc setup}.
|
||||
*/
|
||||
static RouterFunctionSetupBuilder bindToRouterFunction(RouterFunction<?>... routerFunctions) {
|
||||
return new DefaultRestTestClientBuilder.DefaultRouterFunctionSetupBuilder(routerFunctions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Begin creating a {@link RestTestClient} by providing a
|
||||
* {@link WebApplicationContext} with Spring MVC infrastructure and
|
||||
* controllers.
|
||||
* <p>Internally this is delegated to and equivalent to using
|
||||
* {@link org.springframework.test.web.servlet.setup.MockMvcBuilders#webAppContextSetup(WebApplicationContext)}
|
||||
* to initialize {@code MockMvc}.
|
||||
* Begin creating a {@link RestTestClient} with a {@link MockMvcBuilders#webAppContextSetup}
|
||||
* WebAppContext MockMvc setup}.
|
||||
*/
|
||||
static WebAppContextSetupBuilder bindToApplicationContext(WebApplicationContext context) {
|
||||
return new DefaultRestTestClientBuilder.DefaultWebAppContextSetupBuilder(context);
|
||||
@@ -164,8 +167,7 @@ public interface RestTestClient {
|
||||
}
|
||||
|
||||
/**
|
||||
* This server setup option allows you to connect to a live server through
|
||||
* a client connector.
|
||||
* This server setup option allows you to connect to a live server.
|
||||
* <p><pre class="code">
|
||||
* RestTestClient client = RestTestClient.bindToServer()
|
||||
* .baseUrl("http://localhost:8080")
|
||||
@@ -186,12 +188,14 @@ public interface RestTestClient {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Steps to customize the underlying {@link RestClient} via {@link RestClient.Builder}.
|
||||
* @param <B> the type of builder
|
||||
*/
|
||||
interface Builder<B extends Builder<B>> {
|
||||
|
||||
/**
|
||||
* Configure a base URI as described in
|
||||
* {@link RestClient#create(String)
|
||||
* WebClient.create(String)}.
|
||||
* Configure a base URI as described in {@link RestClient#create(String)}.
|
||||
*/
|
||||
<T extends B> T baseUrl(String baseUrl);
|
||||
|
||||
@@ -203,7 +207,7 @@ public interface RestTestClient {
|
||||
|
||||
/**
|
||||
* Add the given header to all requests that haven't added it.
|
||||
* @param headerName the header name
|
||||
* @param headerName the header name
|
||||
* @param headerValues the header values
|
||||
*/
|
||||
<T extends B> T defaultHeader(String headerName, String... headerValues);
|
||||
@@ -220,8 +224,8 @@ public interface RestTestClient {
|
||||
<T extends B> T defaultHeaders(Consumer<HttpHeaders> headersConsumer);
|
||||
|
||||
/**
|
||||
* Add the given cookie to all requests.
|
||||
* @param cookieName the cookie name
|
||||
* Add the given cookie to all requests that haven't already added it.
|
||||
* @param cookieName the cookie name
|
||||
* @param cookieValues the cookie values
|
||||
*/
|
||||
<T extends B> T defaultCookie(String cookieName, String... cookieValues);
|
||||
@@ -237,39 +241,48 @@ public interface RestTestClient {
|
||||
*/
|
||||
<T extends B> T defaultCookies(Consumer<MultiValueMap<String, String>> cookiesConsumer);
|
||||
|
||||
/**
|
||||
* Apply the given {@code Consumer} to this builder instance.
|
||||
* <p>This can be useful for applying pre-packaged customizations.
|
||||
* @param builderConsumer the consumer to apply
|
||||
*/
|
||||
<T extends B> T apply(Consumer<Builder<B>> builderConsumer);
|
||||
|
||||
/**
|
||||
* Build the {@link RestTestClient} instance.
|
||||
*/
|
||||
RestTestClient build();
|
||||
}
|
||||
|
||||
|
||||
interface MockMvcSetupBuilder<B extends Builder<B>, M extends MockMvcBuilder> extends Builder<B> {
|
||||
|
||||
<T extends B> T configureServer(Consumer<M> consumer);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Extension of {@link Builder} for tests against a MockMvc server.
|
||||
* @param <S> the builder type
|
||||
* @param <M> the type of {@link MockMvc} setup
|
||||
*/
|
||||
interface MockMvcSetupBuilder<S extends Builder<S>, M extends MockMvcBuilder> extends Builder<S> {
|
||||
|
||||
<T extends S> T configureServer(Consumer<M> consumer);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Extension of {@link Builder} for tests витх а
|
||||
* {@link MockMvcBuilders#standaloneSetup(Object...) standalone MockMvc setup}.
|
||||
*/
|
||||
interface StandaloneSetupBuilder extends MockMvcSetupBuilder<StandaloneSetupBuilder, StandaloneMockMvcBuilder> {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Extension of {@link Builder} for tests витх а
|
||||
* {@link MockMvcBuilders#routerFunctions(RouterFunction[]) RouterFunction MockMvc setup}.
|
||||
*/
|
||||
interface RouterFunctionSetupBuilder extends MockMvcSetupBuilder<RouterFunctionSetupBuilder, RouterFunctionMockMvcBuilder> {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Extension of {@link Builder} for tests витх а
|
||||
* {@link MockMvcBuilders#webAppContextSetup(WebApplicationContext) WebAppContext MockMvc setup}.
|
||||
*/
|
||||
interface WebAppContextSetupBuilder extends MockMvcSetupBuilder<WebAppContextSetupBuilder, DefaultMockMvcBuilder> {
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Specification for providing the URI of a request.
|
||||
*
|
||||
@@ -294,7 +307,7 @@ public interface RestTestClient {
|
||||
* with a base URI) it will be used to expand the URI template.
|
||||
* @return spec to add headers or perform the exchange
|
||||
*/
|
||||
S uri(String uri, Object... uriVariables);
|
||||
S uri(String uri, @Nullable Object... uriVariables);
|
||||
|
||||
/**
|
||||
* Specify the URI for the request using a URI template and URI variables.
|
||||
@@ -302,7 +315,7 @@ public interface RestTestClient {
|
||||
* with a base URI) it will be used to expand the URI template.
|
||||
* @return spec to add headers or perform the exchange
|
||||
*/
|
||||
S uri(String uri, Map<String, ?> uriVariables);
|
||||
S uri(String uri, Map<String, ? extends @Nullable Object> uriVariables);
|
||||
|
||||
/**
|
||||
* Build the URI for the request with a {@link UriBuilder} obtained
|
||||
@@ -419,6 +432,16 @@ public interface RestTestClient {
|
||||
* Specification for providing body of a request.
|
||||
*/
|
||||
interface RequestBodySpec extends RequestHeadersSpec<RequestBodySpec> {
|
||||
|
||||
/**
|
||||
* Set the length of the body in bytes, as specified by the
|
||||
* {@code Content-Length} header.
|
||||
* @param contentLength the content length
|
||||
* @return the same instance
|
||||
* @see HttpHeaders#setContentLength(long)
|
||||
*/
|
||||
RequestBodySpec contentLength(long contentLength);
|
||||
|
||||
/**
|
||||
* Set the {@linkplain MediaType media type} of the body, as specified
|
||||
* by the {@code Content-Type} header.
|
||||
@@ -430,7 +453,7 @@ public interface RestTestClient {
|
||||
|
||||
/**
|
||||
* Set the body to the given {@code Object} value. This method invokes the
|
||||
* {@link org.springframework.web.client.RestClient.RequestBodySpec#body(Object)} (Object)
|
||||
* {@link RestClient.RequestBodySpec#body(Object)} (Object)
|
||||
* bodyValue} method on the underlying {@code RestClient}.
|
||||
* @param body the value to write to the request body
|
||||
* @return spec for further declaration of the request
|
||||
@@ -461,8 +484,8 @@ public interface RestTestClient {
|
||||
interface ResponseSpec {
|
||||
|
||||
/**
|
||||
* Apply multiple assertions to a response with the given
|
||||
* {@linkplain RestTestClient.ResponseSpec.ResponseSpecConsumer consumers}, with the guarantee that
|
||||
s * Apply multiple assertions to a response with the given
|
||||
* {@linkplain ResponseSpecConsumer consumers}, with the guarantee that
|
||||
* all assertions will be applied even if one or more assertions fails
|
||||
* with an exception.
|
||||
* <p>If a single {@link Error} or {@link RuntimeException} is thrown,
|
||||
@@ -522,8 +545,7 @@ public interface RestTestClient {
|
||||
BodyContentSpec expectBody();
|
||||
|
||||
/**
|
||||
* Exit the chained flow in order to consume the response body
|
||||
* externally.
|
||||
* Exit the chained flow in order to consume the response body externally.
|
||||
*/
|
||||
<T> EntityExchangeResult<T> returnResult(Class<T> elementClass);
|
||||
|
||||
@@ -534,8 +556,8 @@ public interface RestTestClient {
|
||||
<T> EntityExchangeResult<T> returnResult(ParameterizedTypeReference<T> elementTypeRef);
|
||||
|
||||
/**
|
||||
* {@link Consumer} of a {@link RestTestClient.ResponseSpec}.
|
||||
* @see RestTestClient.ResponseSpec#expectAll(RestTestClient.ResponseSpec.ResponseSpecConsumer...)
|
||||
* {@link Consumer} of a {@link ResponseSpec}.
|
||||
* @see ResponseSpec#expectAll(ResponseSpecConsumer...)
|
||||
*/
|
||||
@FunctionalInterface
|
||||
interface ResponseSpecConsumer extends Consumer<ResponseSpec> {
|
||||
@@ -554,18 +576,24 @@ public interface RestTestClient {
|
||||
/**
|
||||
* Assert the extracted body is equal to the given value.
|
||||
*/
|
||||
<T extends S> T isEqualTo(B expected);
|
||||
<T extends S> T isEqualTo(@Nullable B expected);
|
||||
|
||||
/**
|
||||
* Assert the extracted body with a {@link Matcher}.
|
||||
* @since 5.1
|
||||
*/
|
||||
<T extends S> T value(Matcher<? super @Nullable B> matcher);
|
||||
|
||||
/**
|
||||
* Transform the extracted the body with a function, for example, extracting a
|
||||
* property, and assert the mapped value with a {@link Matcher}.
|
||||
*/
|
||||
<T extends S, R> T value(Function<B, R> bodyMapper, Matcher<? super R> matcher);
|
||||
<T extends S, R> T value(Function<@Nullable B, @Nullable R> bodyMapper, Matcher<? super @Nullable R> matcher);
|
||||
|
||||
/**
|
||||
* Assert the extracted body with a {@link Consumer}.
|
||||
*/
|
||||
<T extends S> T value(Consumer<B> consumer);
|
||||
<T extends S> T value(Consumer<@Nullable B> consumer);
|
||||
|
||||
/**
|
||||
* Assert the exchange result with the given {@link Consumer}.
|
||||
|
||||
+3
-1
@@ -29,10 +29,12 @@ import org.springframework.test.web.support.AbstractStatusAssertions;
|
||||
*/
|
||||
public class StatusAssertions extends AbstractStatusAssertions<ExchangeResult, RestTestClient.ResponseSpec> {
|
||||
|
||||
public StatusAssertions(ExchangeResult exchangeResult, ResponseSpec responseSpec) {
|
||||
|
||||
StatusAssertions(ExchangeResult exchangeResult, ResponseSpec responseSpec) {
|
||||
super(exchangeResult, responseSpec);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void assertWithDiagnostics(Runnable assertion) {
|
||||
exchangeResult.assertWithDiagnostics(assertion);
|
||||
|
||||
+6
-2
@@ -33,11 +33,15 @@ import org.springframework.util.Assert;
|
||||
*/
|
||||
public class XpathAssertions extends AbstractXpathAssertions<RestTestClient.BodyContentSpec> {
|
||||
|
||||
XpathAssertions(RestTestClient.BodyContentSpec spec,
|
||||
String expression, @Nullable Map<String, String> namespaces, Object... args) {
|
||||
|
||||
XpathAssertions(
|
||||
RestTestClient.BodyContentSpec spec,
|
||||
String expression, @Nullable Map<String, String> namespaces, Object... args) {
|
||||
|
||||
super(spec, expression, namespaces, args);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected Optional<HttpHeaders> getResponseHeaders() {
|
||||
return Optional.of(bodySpec.returnResult())
|
||||
|
||||
Reference in New Issue
Block a user