From 9829a620444fdd481457004358b1bfa4df222499 Mon Sep 17 00:00:00 2001 From: Rossen Stoyanchev Date: Fri, 17 Feb 2017 22:58:32 -0500 Subject: [PATCH] Refactor WebTestClient assertions take 3 WebTestClient now defines all the steps from setup to performing an exchange and applying expectations. The order of expectations now ensures the response status and headers are verified first since that's available before the body is consumed and also because it determines how the body is to be decoded, i.e. error vs success scenarios. There is now a built-in option for verifying the response as a Map along with Map-specific assertions. There are similar options for verifying the response as a List as well as whether to "collect" the list or "take" the first N elements from the response stream. --- .../reactive/server/DefaultWebTestClient.java | 308 +++++++++++++++--- .../web/reactive/server/ExchangeResult.java | 62 ++-- .../web/reactive/server/HeaderAssertions.java | 42 +-- .../web/reactive/server/LoggingActions.java | 110 ------- .../reactive/server/ResponseAssertions.java | 66 ---- .../web/reactive/server/StatusAssertions.java | 86 ++--- .../web/reactive/server/WebTestClient.java | 202 +++++++++--- .../web/reactive/server/WiretapConnector.java | 23 +- .../server/WiretapConnectorTests.java | 4 +- .../reactive/server/samples/ErrorTests.java | 10 +- .../reactive/server/samples/HeaderTests.java | 12 +- .../server/samples/ResponseEntityTests.java | 45 ++- .../samples/bind/ApplicationContextTests.java | 6 +- .../server/samples/bind/ControllerTests.java | 6 +- .../server/samples/bind/HttpServerTests.java | 6 +- .../samples/bind/RouterFunctionTests.java | 6 +- 16 files changed, 586 insertions(+), 408 deletions(-) delete mode 100644 spring-test/src/main/java/org/springframework/test/web/reactive/server/LoggingActions.java delete mode 100644 spring-test/src/main/java/org/springframework/test/web/reactive/server/ResponseAssertions.java diff --git a/spring-test/src/main/java/org/springframework/test/web/reactive/server/DefaultWebTestClient.java b/spring-test/src/main/java/org/springframework/test/web/reactive/server/DefaultWebTestClient.java index 5535cadc2f9..96effcdfa5d 100644 --- a/spring-test/src/main/java/org/springframework/test/web/reactive/server/DefaultWebTestClient.java +++ b/spring-test/src/main/java/org/springframework/test/web/reactive/server/DefaultWebTestClient.java @@ -19,6 +19,7 @@ import java.net.URI; import java.nio.charset.Charset; import java.time.Duration; import java.time.ZonedDateTime; +import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.Optional; @@ -26,6 +27,7 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicLong; import java.util.function.Consumer; import java.util.function.Function; +import java.util.stream.Collectors; import org.reactivestreams.Publisher; import reactor.core.publisher.Flux; @@ -34,10 +36,10 @@ import reactor.core.publisher.Mono; import org.springframework.core.ResolvableType; import org.springframework.core.io.buffer.DataBuffer; import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; import org.springframework.http.MediaType; import org.springframework.http.client.reactive.ClientHttpConnector; import org.springframework.http.client.reactive.ClientHttpRequest; -import org.springframework.test.util.AssertionErrors; import org.springframework.util.Assert; import org.springframework.util.MultiValueMap; import org.springframework.web.reactive.function.BodyInserter; @@ -46,6 +48,9 @@ import org.springframework.web.reactive.function.client.ExchangeFilterFunction; import org.springframework.web.reactive.function.client.WebClient; import org.springframework.web.util.UriBuilder; +import static org.springframework.test.util.AssertionErrors.assertEquals; +import static org.springframework.test.util.AssertionErrors.assertTrue; +import static org.springframework.test.util.AssertionErrors.fail; import static org.springframework.web.reactive.function.BodyExtractors.toDataBuffers; import static org.springframework.web.reactive.function.BodyExtractors.toFlux; import static org.springframework.web.reactive.function.BodyExtractors.toMono; @@ -242,88 +247,301 @@ class DefaultWebTestClient implements WebTestClient { @Override public ResponseSpec exchange() { - return new DefaultResponseSpec(this.requestId, this.headerSpec.exchange()); + return createResponseSpec(this.headerSpec.exchange()); } @Override public ResponseSpec exchange(BodyInserter inserter) { - return new DefaultResponseSpec(this.requestId, this.headerSpec.exchange(inserter)); + return createResponseSpec(this.headerSpec.exchange(inserter)); } @Override public > ResponseSpec exchange(S publisher, Class elementClass) { - return new DefaultResponseSpec(this.requestId, this.headerSpec.exchange(publisher, elementClass)); + return createResponseSpec(this.headerSpec.exchange(publisher, elementClass)); } + + protected DefaultResponseSpec createResponseSpec(Mono responseMono) { + ClientResponse response = responseMono.block(getTimeout()); + WiretapConnector.Info info = connectorListener.retrieveRequest(this.requestId); + HttpMethod method = info.getMethod(); + URI url = info.getUrl(); + HttpHeaders headers = info.getRequestHeaders(); + ExchangeResult> result = ExchangeResult.fromResponse(method, url, headers, response); + return new DefaultResponseSpec(result, response); + } + } - private class DefaultResponseSpec implements ResponseSpec { + private abstract class ResponseSpecSupport { - private final String requestId; + private final ExchangeResult> exchangeResult; + + private final ClientResponse response; + + + public ResponseSpecSupport(ExchangeResult> result, ClientResponse response) { + this.exchangeResult = result; + this.response = response; + } - private final Mono responseMono; + public ResponseSpecSupport(ResponseSpecSupport responseSpec) { + this.exchangeResult = responseSpec.getExchangeResult(); + this.response = responseSpec.getResponse(); + } + + + protected ExchangeResult> getExchangeResult() { + return this.exchangeResult; + } + protected ClientResponse getResponse() { + return this.response; + } + + protected HttpHeaders getResponseHeaders() { + return getExchangeResult().getResponseHeaders(); + } - public DefaultResponseSpec(String requestId, Mono responseMono) { - this.requestId = requestId; - this.responseMono = responseMono; + protected ExchangeResult createResultWithDecodedBody(T body) { + return ExchangeResult.withDecodedBody(this.exchangeResult, body); + } + + } + + private class DefaultResponseSpec extends ResponseSpecSupport implements ResponseSpec { + + + public DefaultResponseSpec(ExchangeResult> result, ClientResponse response) { + super(result, response); } @Override - public ExchangeResult decodeEntity(Class entityClass) { - return decodeEntity(ResolvableType.forClass(entityClass)); + public StatusAssertions expectStatus() { + return new StatusAssertions(getResponse().statusCode(), this); } @Override - public ExchangeResult> decodeAndCollect(Class elementClass) { - return decodeAndCollect(ResolvableType.forClass(elementClass)); + public HeaderAssertions expectHeader() { + return new HeaderAssertions(getResponseHeaders(), this); } @Override - public ExchangeResult> decodeFlux(Class elementClass) { - return decodeFlux(ResolvableType.forClass(elementClass)); + public BodySpec expectBody() { + return new DefaultBodySpec(this); } @Override - public ExchangeResult decodeEntity(ResolvableType elementType) { - return this.responseMono.then(response -> { - Mono entityMono = response.body(toMono(elementType)); - return entityMono.map(entity -> createTestExchange(entity, response)); - }).block(getTimeout()); + public ElementBodySpec expectBody(Class elementType) { + return expectBody(ResolvableType.forClass(elementType)); } @Override - public ExchangeResult> decodeAndCollect(ResolvableType elementType) { - return this.responseMono.then(response -> { - Flux entityFlux = response.body(toFlux(elementType)); - return entityFlux.collectList().map(list -> createTestExchange(list, response)); - }).block(getTimeout()); + public ElementBodySpec expectBody(ResolvableType elementType) { + return new DefaultElementBodySpec(this, elementType); } @Override - public ExchangeResult> decodeFlux(ResolvableType elementType) { - return this.responseMono.map(response -> { - Flux entityFlux = response.body(toFlux(elementType)); - return createTestExchange(entityFlux, response); - }).block(getTimeout()); + public ResponseSpec consumeWith(Consumer>> consumer) { + consumer.accept(getExchangeResult()); + return this; } @Override - public ExchangeResult expectNoBody() { - return this.responseMono.map(response -> { - DataBuffer buffer = response.body(toDataBuffers()).blockFirst(getTimeout()); - AssertionErrors.assertTrue("Expected empty body", buffer == null); - ExchangeResult exchange = createTestExchange(null, response); - return exchange; - }).block(getTimeout()); + public ExchangeResult> returnResult() { + return getExchangeResult(); + } + } + + private class DefaultBodySpec extends ResponseSpecSupport implements BodySpec { + + + public DefaultBodySpec(ResponseSpecSupport responseSpec) { + super(responseSpec); + } + + + @Override + public ExchangeResult isEmpty() { + DataBuffer buffer = getResponse().body(toDataBuffers()).blockFirst(getTimeout()); + assertTrue("Expected empty body", buffer == null); + return createResultWithDecodedBody(null); } - private ExchangeResult createTestExchange(T body, ClientResponse response) { - WiretapConnector.Info wiretapInfo = connectorListener.retrieveRequest(requestId); - ClientHttpRequest request = wiretapInfo.getRequest(); - return new ExchangeResult( - request.getMethod(), request.getURI(), request.getHeaders(), - response.statusCode(), response.headers().asHttpHeaders(), body); + @Override + public MapBodySpec map(Class keyType, Class valueType) { + return map(ResolvableType.forClass(keyType), ResolvableType.forClass(valueType)); + } + + @Override + public MapBodySpec map(ResolvableType keyType, ResolvableType valueType) { + return new DefaultMapBodySpec(this, keyType, valueType); + } + } + + private class DefaultMapBodySpec extends ResponseSpecSupport implements MapBodySpec { + + private final Map body; + + + public DefaultMapBodySpec(ResponseSpecSupport spec, ResolvableType keyType, ResolvableType valueType) { + super(spec); + ResolvableType mapType = ResolvableType.forClassWithGenerics(Map.class, keyType, valueType); + this.body = (Map) spec.getResponse().body(toMono(mapType)).block(getTimeout()); + } + + + @Override + public ExchangeResult> isEqualTo(Map expected) { + return returnResult(); + } + + @Override + public MapBodySpec hasSize(int size) { + assertEquals("Response body map size", size, this.body.size()); + return this; + } + + @Override + public MapBodySpec contains(Object key, Object value) { + assertEquals("Response body map value for key " + key, value, this.body.get(key)); + return this; + } + + @Override + public MapBodySpec containsKeys(Object... keys) { + List missing = Arrays.stream(keys) + .filter(key -> !this.body.containsKey(key)) + .collect(Collectors.toList()); + if (!missing.isEmpty()) { + fail("Response body map does not contain keys " + Arrays.toString(keys)); + } + return this; + } + + @Override + public MapBodySpec containsValues(Object... values) { + List missing = Arrays.stream(values) + .filter(value -> !this.body.containsValue(value)) + .collect(Collectors.toList()); + if (!missing.isEmpty()) { + fail("Response body map does not contain values " + Arrays.toString(values)); + } + return this; + } + + @Override + @SuppressWarnings("unchecked") + public ExchangeResult> returnResult() { + return createResultWithDecodedBody((Map) this.body); + } + } + + private class DefaultElementBodySpec extends ResponseSpecSupport implements ElementBodySpec { + + private final ResolvableType elementType; + + + public DefaultElementBodySpec(ResponseSpecSupport spec, ResolvableType elementType) { + super(spec); + this.elementType = elementType; + } + + + @Override + public SingleValueBodySpec value() { + return new DefaultSingleValueBodySpec(this, this.elementType); + } + + @Override + public ListBodySpec list() { + return new DefaultListBodySpec(this, this.elementType, -1); + } + + @Override + public ListBodySpec list(int elementCount) { + return new DefaultListBodySpec(this, this.elementType, elementCount); + } + + @Override + public ExchangeResult> returnResult() { + Flux flux = getResponse().body(toFlux(this.elementType)); + return createResultWithDecodedBody(flux); + } + } + + private class DefaultSingleValueBodySpec extends ResponseSpecSupport + implements SingleValueBodySpec { + + private final Object body; + + + public DefaultSingleValueBodySpec(ResponseSpecSupport spec, ResolvableType elementType) { + super(spec); + this.body = getResponse().body(toMono(elementType)).block(getTimeout()); + } + + + @Override + public ExchangeResult isEqualTo(Object expected) { + assertEquals("Response body", expected, this.body); + return returnResult(); + } + + @Override + @SuppressWarnings("unchecked") + public ExchangeResult returnResult() { + return createResultWithDecodedBody((T) this.body); + } + } + + private class DefaultListBodySpec extends ResponseSpecSupport + implements ListBodySpec { + + private final List body; + + + public DefaultListBodySpec(ResponseSpecSupport spec, ResolvableType elementType, int elementCount) { + super(spec); + Flux flux = getResponse().body(toFlux(elementType)); + if (elementCount >= 0) { + flux = flux.take(elementCount); + } + this.body = flux.collectList().block(getTimeout()); + } + + + @Override + public ExchangeResult> isEqualTo(List expected) { + assertEquals("Response body", expected, this.body); + return returnResult(); + } + + @Override + public ListBodySpec hasSize(int size) { + return this; + } + + @Override + public ListBodySpec contains(Object... elements) { + List elementList = Arrays.asList(elements); + String message = "Response body does not contain " + elementList; + assertTrue(message, this.body.containsAll(elementList)); + return this; + } + + @Override + public ListBodySpec doesNotContain(Object... elements) { + List elementList = Arrays.asList(elements); + String message = "Response body should have contained " + elementList; + assertTrue(message, !this.body.containsAll(Arrays.asList(elements))); + return this; + } + + @Override + @SuppressWarnings("unchecked") + public ExchangeResult> returnResult() { + return createResultWithDecodedBody((List) this.body); } } @@ -346,7 +564,7 @@ class DefaultWebTestClient implements WebTestClient { @Override public void accept(WiretapConnector.Info info) { - Optional.ofNullable(info.getRequest().getHeaders().getFirst(REQUEST_ID_HEADER_NAME)) + Optional.ofNullable(info.getRequestHeaders().getFirst(REQUEST_ID_HEADER_NAME)) .ifPresent(id -> this.exchanges.put(id, info)); } diff --git a/spring-test/src/main/java/org/springframework/test/web/reactive/server/ExchangeResult.java b/spring-test/src/main/java/org/springframework/test/web/reactive/server/ExchangeResult.java index 72097b2d32d..03b5394d13a 100644 --- a/spring-test/src/main/java/org/springframework/test/web/reactive/server/ExchangeResult.java +++ b/spring-test/src/main/java/org/springframework/test/web/reactive/server/ExchangeResult.java @@ -18,21 +18,21 @@ package org.springframework.test.web.reactive.server; import java.net.URI; import java.util.stream.Collectors; +import reactor.core.publisher.Flux; + +import org.springframework.core.io.buffer.DataBuffer; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.http.HttpStatus; +import org.springframework.web.reactive.function.client.ClientResponse; + +import static org.springframework.web.reactive.function.BodyExtractors.toDataBuffers; /** - * Container for request and response details including the decoded response - * body from an exchange performed through {@link WebTestClient}. - * - *

Use {@link #assertThat()} to access built-in assertions on the response, - * or apply other assertions directly to the data contained in this class. - * The built-in assertions provide an option for logging diagnostic information - * about the exchange. The same can also be obtained using the - * {@link #toString()} method of this class. + * Container for request and response details from an exchange performed + * through {@link WebTestClient}. * - * @param the type of the decoded response body + * @param the type of the response body * * @author Rossen Stoyanchev * @since 5.0 @@ -52,8 +52,11 @@ public class ExchangeResult { private final T responseBody; - public ExchangeResult(HttpMethod method, URI url, HttpHeaders requestHeaders, - HttpStatus status, HttpHeaders responseHeaders, T responseBody) { + /** + * Package private constructor. + */ + ExchangeResult(HttpMethod method, URI url, HttpHeaders requestHeaders, HttpStatus status, + HttpHeaders responseHeaders, T responseBody) { this.method = method; this.url = url; @@ -64,25 +67,17 @@ public class ExchangeResult { } - /** - * Provides access to built-in assertions on the response. - */ - public ResponseAssertions assertThat() { - return new ResponseAssertions(this); - } - - /** * Return the request method of the exchange. */ - public HttpMethod getRequestMethod() { + public HttpMethod getMethod() { return this.method; } /** * Return the URL of the exchange. */ - public URI getRequestUrl() { + public URI getUrl() { return this.url; } @@ -96,7 +91,7 @@ public class ExchangeResult { /** * Return the response status. */ - public HttpStatus getResponseStatus() { + public HttpStatus getStatus() { return this.status; } @@ -115,11 +110,32 @@ public class ExchangeResult { } + /** + * Create an instance from a ClientResponse (body not yet consumed). + */ + static ExchangeResult> fromResponse(HttpMethod method, URI url, + HttpHeaders requestHeaders, ClientResponse response) { + + HttpStatus status = response.statusCode(); + HttpHeaders responseHeaders = response.headers().asHttpHeaders(); + Flux body = response.body(toDataBuffers()); + return new ExchangeResult<>(method, url, requestHeaders, status, responseHeaders, body); + } + + /** + * Re-create the result with a generic type matching the decoded body. + */ + static ExchangeResult withDecodedBody(ExchangeResult result, T body) { + return new ExchangeResult<>(result.getMethod(), result.getUrl(), result.getRequestHeaders(), + result.getStatus(), result.getResponseHeaders(), body); + } + + @Override public String toString() { HttpStatus status = this.status; return "\n\n" + - formatValue("Request", this.method + " " + getRequestUrl()) + + formatValue("Request", this.method + " " + getUrl()) + formatValue("Status", status + " " + status.getReasonPhrase()) + formatHeading("Response Headers") + formatHeaders(this.responseHeaders) + diff --git a/spring-test/src/main/java/org/springframework/test/web/reactive/server/HeaderAssertions.java b/spring-test/src/main/java/org/springframework/test/web/reactive/server/HeaderAssertions.java index be32eed1b12..de1599deea8 100644 --- a/spring-test/src/main/java/org/springframework/test/web/reactive/server/HeaderAssertions.java +++ b/spring-test/src/main/java/org/springframework/test/web/reactive/server/HeaderAssertions.java @@ -35,68 +35,68 @@ import static org.springframework.test.util.AssertionErrors.assertTrue; * @since 5.0 * @see ResponseAssertions#header() */ -public class HeaderAssertions { - - private final ResponseAssertions resultAssertions; +public class HeaderAssertions { private final HttpHeaders headers; + private final WebTestClient.ResponseSpec responseSpec; + - public HeaderAssertions(HttpHeaders headers, ResponseAssertions resultAssertions) { - this.resultAssertions = resultAssertions; + public HeaderAssertions(HttpHeaders headers, WebTestClient.ResponseSpec responseSpec) { this.headers = headers; + this.responseSpec = responseSpec; } - public ResponseAssertions valueEquals(String headerName, String... values) { + public WebTestClient.ResponseSpec valueEquals(String headerName, String... values) { List actual = this.headers.get(headerName); assertEquals("Response header [" + headerName + "]", Arrays.asList(values), actual); - return this.resultAssertions; + return this.responseSpec; } - public ResponseAssertions valueMatches(String headerName, String pattern) { + public WebTestClient.ResponseSpec valueMatches(String headerName, String pattern) { List values = this.headers.get(headerName); String value = CollectionUtils.isEmpty(values) ? "" : values.get(0); boolean match = Pattern.compile(pattern).matcher(value).matches(); String message = "Response header " + headerName + "=\'" + value + "\' does not match " + pattern; assertTrue(message, match); - return this.resultAssertions; + return this.responseSpec; } - public ResponseAssertions cacheControlEquals(CacheControl cacheControl) { + public WebTestClient.ResponseSpec cacheControlEquals(CacheControl cacheControl) { String actual = this.headers.getCacheControl(); assertEquals("Response header Cache-Control", cacheControl.getHeaderValue(), actual); - return this.resultAssertions; + return this.responseSpec; } - public ResponseAssertions contentDispositionEquals(ContentDisposition contentDisposition) { + public WebTestClient.ResponseSpec contentDispositionEquals(ContentDisposition contentDisposition) { ContentDisposition actual = this.headers.getContentDisposition(); assertEquals("Response header Content-Disposition", contentDisposition, actual); - return this.resultAssertions; + return this.responseSpec; } - public ResponseAssertions contentLengthEquals(long contentLength) { + public WebTestClient.ResponseSpec contentLengthEquals(long contentLength) { long actual = this.headers.getContentLength(); assertEquals("Response header Content-Length", contentLength, actual); - return this.resultAssertions; + return this.responseSpec; } - public ResponseAssertions contentTypeEquals(MediaType mediaType) { + public WebTestClient.ResponseSpec contentTypeEquals(MediaType mediaType) { MediaType actual = this.headers.getContentType(); assertEquals("Response header Content-Type", mediaType, actual); - return this.resultAssertions; + return this.responseSpec; } - public ResponseAssertions expiresEquals(int expires) { + public WebTestClient.ResponseSpec expiresEquals(int expires) { long actual = this.headers.getExpires(); assertEquals("Response header Expires", expires, actual); - return this.resultAssertions; + return this.responseSpec; } - public ResponseAssertions lastModifiedEquals(int lastModified) { + public WebTestClient.ResponseSpec lastModifiedEquals(int lastModified) { long actual = this.headers.getLastModified(); assertEquals("Response header Last-Modified", lastModified, actual); - return this.resultAssertions; + return this.responseSpec; } } diff --git a/spring-test/src/main/java/org/springframework/test/web/reactive/server/LoggingActions.java b/spring-test/src/main/java/org/springframework/test/web/reactive/server/LoggingActions.java deleted file mode 100644 index 7ce29c0b9ff..00000000000 --- a/spring-test/src/main/java/org/springframework/test/web/reactive/server/LoggingActions.java +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright 2002-2017 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.springframework.test.web.reactive.server; - -import java.io.IOException; -import java.io.OutputStream; -import java.io.PrintWriter; -import java.io.Writer; -import java.util.function.BiConsumer; -import java.util.function.Predicate; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * Provides options for logging diagnostic information about the exchange. - * - * @author Rossen Stoyanchev - * @since 5.0 - * @see ResponseAssertions#log() - */ -public class LoggingActions { - - private static Log logger = LogFactory.getLog(LoggingActions.class); - - private final ResponseAssertions resultAssertions; - - private final ExchangeResult exchange; - - - public LoggingActions(ExchangeResult exchange, ResponseAssertions resultAssertions) { - this.resultAssertions = resultAssertions; - this.exchange = exchange; - } - - - /** - * Log with {@link System#out}. - */ - public ResponseAssertions toConsole() { - return toOutputStream(System.out); - } - - /** - * Log with a given {@link OutputStream}. - */ - public ResponseAssertions toOutputStream(OutputStream stream) { - return toWriter(new PrintWriter(stream, true)); - } - - /** - * Log with a given {@link Writer}. - */ - public ResponseAssertions toWriter(Writer writer) { - try { - writer.write(getOutput()); - } - catch (IOException ex) { - throw new IllegalStateException("Failed to print exchange info", ex); - } - return this.resultAssertions; - } - - /** - * Log if TRACE level logging is enabled. - */ - public ResponseAssertions ifTraceEnabled() { - return doLog(Log::isTraceEnabled, Log::trace); - } - - /** - * Log if DEBUG level logging is enabled. - */ - public ResponseAssertions ifDebugEnabled() { - return doLog(Log::isDebugEnabled, Log::debug); - } - - /** - * Log if INFO level logging is enabled. - */ - public ResponseAssertions ifInfoEnabled() { - return doLog(Log::isInfoEnabled, Log::info); - } - - - private ResponseAssertions doLog(Predicate predicate, BiConsumer consumer) { - if (predicate.test(logger)) { - consumer.accept(logger, getOutput()); - } - return this.resultAssertions; - } - - private String getOutput() { - return this.resultAssertions.toString(); - } - -} diff --git a/spring-test/src/main/java/org/springframework/test/web/reactive/server/ResponseAssertions.java b/spring-test/src/main/java/org/springframework/test/web/reactive/server/ResponseAssertions.java deleted file mode 100644 index 19a4ccd4979..00000000000 --- a/spring-test/src/main/java/org/springframework/test/web/reactive/server/ResponseAssertions.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright 2002-2017 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.springframework.test.web.reactive.server; - -import static org.springframework.test.util.AssertionErrors.assertEquals; - -/** - * Assertions on an {@code ExchangeResult}. - * - *

Use {@link ExchangeResult#assertThat()} to access these assertions. - * - * @author Rossen Stoyanchev - * @since 5.0 - */ -public class ResponseAssertions { - - private final ExchangeResult exchangeResult; - - - ResponseAssertions(ExchangeResult exchangeResult) { - this.exchangeResult = exchangeResult; - } - - - /** - * Assertions on the response status. - */ - public StatusAssertions status() { - return new StatusAssertions<>(this.exchangeResult.getResponseStatus(), this); - } - - /** - * Assertions on response headers. - */ - public HeaderAssertions header() { - return new HeaderAssertions<>(this.exchangeResult.getResponseHeaders(), this); - } - - /** - * Assert the response body is equal to the given value. - */ - public void bodyEquals(T value) { - assertEquals("Response body", value, this.exchangeResult.getResponseBody()); - } - - /** - * Options for logging diagnostic information. - */ - public LoggingActions log() { - return new LoggingActions(this.exchangeResult, this); - } - -} diff --git a/spring-test/src/main/java/org/springframework/test/web/reactive/server/StatusAssertions.java b/spring-test/src/main/java/org/springframework/test/web/reactive/server/StatusAssertions.java index 8f7d04cbf5f..10c8489fc94 100644 --- a/spring-test/src/main/java/org/springframework/test/web/reactive/server/StatusAssertions.java +++ b/spring-test/src/main/java/org/springframework/test/web/reactive/server/StatusAssertions.java @@ -27,174 +27,174 @@ import static org.springframework.test.util.AssertionErrors.assertEquals; * @see ResponseAssertions#status() */ @SuppressWarnings("unused") -public class StatusAssertions { - - private final ResponseAssertions resultAssertions; +public class StatusAssertions { private final HttpStatus httpStatus; + private final WebTestClient.ResponseSpec responseSpec; + - StatusAssertions(HttpStatus status, ResponseAssertions exchangeActions) { - this.resultAssertions = exchangeActions; + StatusAssertions(HttpStatus status, WebTestClient.ResponseSpec responseSpec) { this.httpStatus = status; + this.responseSpec = responseSpec; } /** * Assert the response status as an {@link HttpStatus}. */ - public ResponseAssertions isEqualTo(HttpStatus status) { + public WebTestClient.ResponseSpec isEqualTo(HttpStatus status) { assertEquals("Response status", status, this.httpStatus); - return this.resultAssertions; + return this.responseSpec; } /** * Assert the response status as an integer. */ - public ResponseAssertions isEqualTo(int status) { + public WebTestClient.ResponseSpec isEqualTo(int status) { assertEquals("Response status", status, this.httpStatus.value()); - return this.resultAssertions; + return this.responseSpec; } /** * Assert the response status code is {@code HttpStatus.OK} (200). */ - public ResponseAssertions isOk() { + public WebTestClient.ResponseSpec isOk() { assertEquals("Status", HttpStatus.OK, this.httpStatus); - return this.resultAssertions; + return this.responseSpec; } /** * Assert the response status code is {@code HttpStatus.CREATED} (201). */ - public ResponseAssertions isCreated() { + public WebTestClient.ResponseSpec isCreated() { assertEquals("Status", HttpStatus.CREATED, this.httpStatus); - return this.resultAssertions; + return this.responseSpec; } /** * Assert the response status code is {@code HttpStatus.ACCEPTED} (202). */ - public ResponseAssertions isAccepted() { + public WebTestClient.ResponseSpec isAccepted() { assertEquals("Status", HttpStatus.ACCEPTED, this.httpStatus); - return this.resultAssertions; + return this.responseSpec; } /** * Assert the response status code is {@code HttpStatus.NO_CONTENT} (204). */ - public ResponseAssertions isNoContent() { + public WebTestClient.ResponseSpec isNoContent() { assertEquals("Status", HttpStatus.NO_CONTENT, this.httpStatus); - return this.resultAssertions; + return this.responseSpec; } /** * Assert the response status code is {@code HttpStatus.FOUND} (302). */ - public ResponseAssertions isFound() { + public WebTestClient.ResponseSpec isFound() { assertEquals("Status", HttpStatus.FOUND, this.httpStatus); - return this.resultAssertions; + return this.responseSpec; } /** * Assert the response status code is {@code HttpStatus.SEE_OTHER} (303). */ - public ResponseAssertions isSeeOther() { + public WebTestClient.ResponseSpec isSeeOther() { assertEquals("Status", HttpStatus.SEE_OTHER, this.httpStatus); - return this.resultAssertions; + return this.responseSpec; } /** * Assert the response status code is {@code HttpStatus.NOT_MODIFIED} (304). */ - public ResponseAssertions isNotModified() { + public WebTestClient.ResponseSpec isNotModified() { assertEquals("Status", HttpStatus.NOT_MODIFIED, this.httpStatus); - return this.resultAssertions; + return this.responseSpec; } /** * Assert the response status code is {@code HttpStatus.TEMPORARY_REDIRECT} (307). */ - public ResponseAssertions isTemporaryRedirect() { + public WebTestClient.ResponseSpec isTemporaryRedirect() { assertEquals("Status", HttpStatus.TEMPORARY_REDIRECT, this.httpStatus); - return this.resultAssertions; + return this.responseSpec; } /** * Assert the response status code is {@code HttpStatus.PERMANENT_REDIRECT} (308). */ - public ResponseAssertions isPermanentRedirect() { + public WebTestClient.ResponseSpec isPermanentRedirect() { assertEquals("Status", HttpStatus.PERMANENT_REDIRECT, this.httpStatus); - return this.resultAssertions; + return this.responseSpec; } /** * Assert the response status code is {@code HttpStatus.BAD_REQUEST} (400). */ - public ResponseAssertions isBadRequest() { + public WebTestClient.ResponseSpec isBadRequest() { assertEquals("Status", HttpStatus.BAD_REQUEST, this.httpStatus); - return this.resultAssertions; + return this.responseSpec; } /** * Assert the response status code is {@code HttpStatus.NOT_FOUND} (404). */ - public ResponseAssertions isNotFound() { + public WebTestClient.ResponseSpec isNotFound() { assertEquals("Status", HttpStatus.NOT_FOUND, this.httpStatus); - return this.resultAssertions; + return this.responseSpec; } /** * Assert the response error message. */ - public ResponseAssertions reasonEquals(String reason) { + public WebTestClient.ResponseSpec reasonEquals(String reason) { assertEquals("Response status reason", reason, this.httpStatus.getReasonPhrase()); - return this.resultAssertions; + return this.responseSpec; } /** * Assert the response status code is in the 1xx range. */ - public ResponseAssertions is1xxInformational() { + public WebTestClient.ResponseSpec is1xxInformational() { String message = "Range for response status value " + this.httpStatus; assertEquals(message, HttpStatus.Series.INFORMATIONAL, this.httpStatus.series()); - return this.resultAssertions; + return this.responseSpec; } /** * Assert the response status code is in the 2xx range. */ - public ResponseAssertions is2xxSuccessful() { + public WebTestClient.ResponseSpec is2xxSuccessful() { String message = "Range for response status value " + this.httpStatus; assertEquals(message, HttpStatus.Series.SUCCESSFUL, this.httpStatus.series()); - return this.resultAssertions; + return this.responseSpec; } /** * Assert the response status code is in the 3xx range. */ - public ResponseAssertions is3xxRedirection() { + public WebTestClient.ResponseSpec is3xxRedirection() { String message = "Range for response status value " + this.httpStatus; assertEquals(message, HttpStatus.Series.REDIRECTION, this.httpStatus.series()); - return this.resultAssertions; + return this.responseSpec; } /** * Assert the response status code is in the 4xx range. */ - public ResponseAssertions is4xxClientError() { + public WebTestClient.ResponseSpec is4xxClientError() { String message = "Range for response status value " + this.httpStatus; assertEquals(message, HttpStatus.Series.CLIENT_ERROR, this.httpStatus.series()); - return this.resultAssertions; + return this.responseSpec; } /** * Assert the response status code is in the 5xx range. */ - public ResponseAssertions is5xxServerError() { + public WebTestClient.ResponseSpec is5xxServerError() { String message = "Range for response status value " + this.httpStatus; assertEquals(message, HttpStatus.Series.SERVER_ERROR, this.httpStatus.series()); - return this.resultAssertions; + return this.responseSpec; } } diff --git a/spring-test/src/main/java/org/springframework/test/web/reactive/server/WebTestClient.java b/spring-test/src/main/java/org/springframework/test/web/reactive/server/WebTestClient.java index 5b0d283e7ef..b31af720dc8 100644 --- a/spring-test/src/main/java/org/springframework/test/web/reactive/server/WebTestClient.java +++ b/spring-test/src/main/java/org/springframework/test/web/reactive/server/WebTestClient.java @@ -29,6 +29,7 @@ import reactor.core.publisher.Flux; import org.springframework.context.ApplicationContext; import org.springframework.core.ResolvableType; +import org.springframework.core.io.buffer.DataBuffer; import org.springframework.format.FormatterRegistry; import org.springframework.http.HttpHeaders; import org.springframework.http.MediaType; @@ -447,72 +448,191 @@ public interface WebTestClient { } /** - * Specification for decoding the response of an exchange. + * Specification for expectations on the response. */ interface ResponseSpec { /** - * Decode the response as a single entity of the given type. - * @param entityClass the entity type - * @param the type of entity - * @return container for the result of the exchange + * Assertions on the response status. */ - ExchangeResult decodeEntity(Class entityClass); + StatusAssertions expectStatus(); /** - * Alternative to {@link #decodeEntity(Class)} useful for entity - * types with generics. - * @param entityType the type of entity - * @param the type of entity - * @return container for the result of the exchange - * @see ResolvableType#forClassWithGenerics(Class, Class[]) + * Assertions on the response headers. */ - ExchangeResult decodeEntity(ResolvableType entityType); + HeaderAssertions expectHeader(); /** - * Decode the response as a finite stream of the given element type and - * collect the items into a list. - * @param elementClass the list element type - * @param the type of list elements - * @return container for the result of the exchange + * Assertions on the response body. */ - ExchangeResult> decodeAndCollect(Class elementClass); + BodySpec expectBody(); /** - * Alternative to {@link #decodeAndCollect(Class)} useful for element - * types with generics. - * @param elementType the list element type - * @param the type of list elements - * @return container for the result of the exchange - * @see ResolvableType#forClassWithGenerics(Class, Class[]) + * Assertions on the response body where the body is to be decoded to + * one or more elements of the given type. */ - ExchangeResult> decodeAndCollect(ResolvableType elementType); + ElementBodySpec expectBody(Class elementType); /** - * Turn the response stream of byte buffers into a stream of Objects of - * the given type. - * @param elementClass the stream element type - * @param the type of stream elements - * @return container for the result of the exchange + * Alternative to {@link #expectBody(Class)} for generic types. */ - ExchangeResult> decodeFlux(Class elementClass); + ElementBodySpec expectBody(ResolvableType elementType); /** - * Alternative to {@link #decodeFlux(Class)} useful for element types - * with generics. - * @param elementType the stream element type - * @param the type of stream elements - * @return container for the result of the exchange - * @see ResolvableType#forClassWithGenerics(Class, Class[]) + * Consume the result of the exchange and continue with expectations. */ - ExchangeResult> decodeFlux(ResolvableType elementType); + ResponseSpec consumeWith(Consumer>> consumer); + + /** + * Return a container for the result of the exchange with the body + * not yet decoded nor consumed. + */ + ExchangeResult> returnResult(); + } + + /** + * Specification for expectations on the body of the response. + */ + interface BodySpec { /** - * Consume the response and verify there is no content. + * Consume the body and verify it is empty. * @return container for the result of the exchange */ - ExchangeResult expectNoBody(); + ExchangeResult isEmpty(); + + /** + * Decode the response body as a Map with the given key and value type. + */ + MapBodySpec map(Class keyType, Class valueType); + + /** + * Alternative to {@link #map(Class, Class)} for generic types. + */ + MapBodySpec map(ResolvableType keyType, ResolvableType valueType); + + } + + /** + * Specification for expectations on the body of the response decoded as a map. + */ + interface MapBodySpec { + + /** + * Assert the decoded body is equal to the given list of elements. + */ + ExchangeResult> isEqualTo(Map expected); + + /** + * Assert the decoded map has the given size. + * @param size the expected size + */ + MapBodySpec hasSize(int size); + + /** + * Assert the decoded map contains the given key value pair. + * @param key the key to check + * @param value the value to check + */ + MapBodySpec contains(Object key, Object value); + + /** + * Assert the decoded map contains the given keys. + * @param keys the keys to check + */ + MapBodySpec containsKeys(Object... keys); + + /** + * Assert the decoded map contains the given values. + * @param values the keys to check + */ + MapBodySpec containsValues(Object... values); + + /** + * Return a container for the result of the exchange. + */ + ExchangeResult> returnResult(); + } + + /** + * Specification for expectations on the body of the response to be decoded + * as one or more elements of a specific type. + */ + interface ElementBodySpec { + + /** + * Decode the response as a single element. + */ + SingleValueBodySpec value(); + + /** + * Decode the response as a Flux of objects and collect it to a list. + */ + ListBodySpec list(); + + /** + * Decode the response as a Flux of objects consuming only the specified + * number of elements. + */ + ListBodySpec list(int elementCount); + + /** + * Decode the response as a Flux of objects and return a container for + * the result where the response body not yet consumed. + */ + ExchangeResult> returnResult(); + } + + /** + * Specification for expectations on the body of the response decoded as a + * single element of a specific type. + */ + interface SingleValueBodySpec { + + /** + * Assert the decoded body is equal to the given value. + */ + ExchangeResult isEqualTo(Object expected); + /** + * Return a container for the result of the exchange. + */ + ExchangeResult returnResult(); + } + + /** + * Specification for expectations on the body of the response decoded as a + * list of elements of a specific type. + */ + interface ListBodySpec { + + /** + * Assert the decoded body is equal to the given list of elements. + */ + ExchangeResult> isEqualTo(List expected); + + /** + * Assert the decoded list of values is of the given size. + * @param size the expected size + */ + ListBodySpec hasSize(int size); + + /** + * Assert the decoded list of values contains the given elements. + * @param elements the elements to check + */ + ListBodySpec contains(Object... elements); + + /** + * Assert the decoded list of values does not contain the given elements. + * @param elements the elements to check + */ + ListBodySpec doesNotContain(Object... elements); + + /** + * Return a container for the result of the exchange. + */ + ExchangeResult> returnResult(); } } diff --git a/spring-test/src/main/java/org/springframework/test/web/reactive/server/WiretapConnector.java b/spring-test/src/main/java/org/springframework/test/web/reactive/server/WiretapConnector.java index d5497750f8f..98170a17372 100644 --- a/spring-test/src/main/java/org/springframework/test/web/reactive/server/WiretapConnector.java +++ b/spring-test/src/main/java/org/springframework/test/web/reactive/server/WiretapConnector.java @@ -24,6 +24,7 @@ import java.util.function.Function; import reactor.core.publisher.Mono; +import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.http.client.reactive.ClientHttpConnector; import org.springframework.http.client.reactive.ClientHttpRequest; @@ -79,19 +80,33 @@ class WiretapConnector implements ClientHttpConnector { public static class Info { - private final ClientHttpRequest request; + private final HttpMethod method; + + private final URI url; + + private final HttpHeaders requestHeaders; private final ClientHttpResponse response; public Info(ClientHttpRequest request, ClientHttpResponse response) { - this.request = request; + this.method = request.getMethod(); + this.url = request.getURI(); + this.requestHeaders = request.getHeaders(); this.response = response; } - public ClientHttpRequest getRequest() { - return this.request; + public HttpMethod getMethod() { + return this.method; + } + + public URI getUrl() { + return this.url; + } + + public HttpHeaders getRequestHeaders() { + return this.requestHeaders; } public ClientHttpResponse getResponse() { diff --git a/spring-test/src/test/java/org/springframework/test/web/reactive/server/WiretapConnectorTests.java b/spring-test/src/test/java/org/springframework/test/web/reactive/server/WiretapConnectorTests.java index 622379ec44d..cfebc34d207 100644 --- a/spring-test/src/test/java/org/springframework/test/web/reactive/server/WiretapConnectorTests.java +++ b/spring-test/src/test/java/org/springframework/test/web/reactive/server/WiretapConnectorTests.java @@ -33,6 +33,7 @@ import org.springframework.web.reactive.function.client.ClientRequest; import org.springframework.web.reactive.function.client.ExchangeFunction; import org.springframework.web.reactive.function.client.ExchangeFunctions; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertSame; @@ -60,7 +61,8 @@ public class WiretapConnectorTests { WiretapConnector.Info info = infoRef.get(); assertNotNull(info); - assertSame(request, info.getRequest()); + assertEquals(HttpMethod.GET, info.getMethod()); + assertEquals("/test", info.getUrl().toString()); assertSame(response, info.getResponse()); } diff --git a/spring-test/src/test/java/org/springframework/test/web/reactive/server/samples/ErrorTests.java b/spring-test/src/test/java/org/springframework/test/web/reactive/server/samples/ErrorTests.java index 987fcf0eddf..d8a2f86c238 100644 --- a/spring-test/src/test/java/org/springframework/test/web/reactive/server/samples/ErrorTests.java +++ b/spring-test/src/test/java/org/springframework/test/web/reactive/server/samples/ErrorTests.java @@ -44,18 +44,16 @@ public class ErrorTests { public void notFound() throws Exception { this.client.get().uri("/invalid") .exchange() - .expectNoBody() - .assertThat() - .status().isNotFound(); + .expectStatus().isNotFound() + .expectBody().isEmpty(); } @Test public void serverException() throws Exception { this.client.get().uri("/server-error") .exchange() - .expectNoBody() - .assertThat() - .status().isEqualTo(HttpStatus.INTERNAL_SERVER_ERROR); + .expectStatus().isEqualTo(HttpStatus.INTERNAL_SERVER_ERROR) + .expectBody().isEmpty(); } diff --git a/spring-test/src/test/java/org/springframework/test/web/reactive/server/samples/HeaderTests.java b/spring-test/src/test/java/org/springframework/test/web/reactive/server/samples/HeaderTests.java index efe554925e8..9f901d83fc0 100644 --- a/spring-test/src/test/java/org/springframework/test/web/reactive/server/samples/HeaderTests.java +++ b/spring-test/src/test/java/org/springframework/test/web/reactive/server/samples/HeaderTests.java @@ -49,20 +49,16 @@ public class HeaderTests { public void requestResponseHeaderPair() throws Exception { this.client.get().uri("/request-response-pair").header("h1", "in") .exchange() - .expectNoBody() - .assertThat() - .status().isOk() - .header().valueEquals("h1", "in-out"); + .expectStatus().isOk() + .expectHeader().valueEquals("h1", "in-out"); } @Test public void headerMultivalue() throws Exception { this.client.get().uri("/multivalue") .exchange() - .expectNoBody() - .assertThat() - .status().isOk() - .header().valueEquals("h1", "v1", "v2", "v3"); + .expectStatus().isOk() + .expectHeader().valueEquals("h1", "v1", "v2", "v3"); } diff --git a/spring-test/src/test/java/org/springframework/test/web/reactive/server/samples/ResponseEntityTests.java b/spring-test/src/test/java/org/springframework/test/web/reactive/server/samples/ResponseEntityTests.java index c3f0e598c84..df0f80cdd46 100644 --- a/spring-test/src/test/java/org/springframework/test/web/reactive/server/samples/ResponseEntityTests.java +++ b/spring-test/src/test/java/org/springframework/test/web/reactive/server/samples/ResponseEntityTests.java @@ -18,6 +18,7 @@ package org.springframework.test.web.reactive.server.samples; import java.net.URI; import java.util.Arrays; import java.util.LinkedHashMap; +import java.util.List; import java.util.Map; import com.fasterxml.jackson.annotation.JsonCreator; @@ -28,7 +29,6 @@ import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import reactor.test.StepVerifier; -import org.springframework.core.ResolvableType; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.test.web.reactive.server.ExchangeResult; @@ -65,22 +65,22 @@ public class ResponseEntityTests { public void entity() throws Exception { this.client.get().uri("/persons/John") .exchange() - .decodeEntity(Person.class) - .assertThat() - .status().isOk() - .header().contentTypeEquals(MediaType.APPLICATION_JSON_UTF8) - .bodyEquals(new Person("John")); + .expectStatus().isOk() + .expectHeader().contentTypeEquals(MediaType.APPLICATION_JSON_UTF8) + .expectBody(Person.class).value().isEqualTo(new Person("John")); } @Test public void entityList() throws Exception { + + List expected = Arrays.asList( + new Person("Jane"), new Person("Jason"), new Person("John")); + this.client.get().uri("/persons") .exchange() - .decodeAndCollect(Person.class) - .assertThat() - .status().isOk() - .header().contentTypeEquals(MediaType.APPLICATION_JSON_UTF8) - .bodyEquals(Arrays.asList(new Person("Jane"), new Person("Jason"), new Person("John"))); + .expectStatus().isOk() + .expectHeader().contentTypeEquals(MediaType.APPLICATION_JSON_UTF8) + .expectBody(Person.class).list().isEqualTo(expected); } @Test @@ -93,10 +93,9 @@ public class ResponseEntityTests { this.client.get().uri("/persons?map=true") .exchange() - .decodeEntity(ResolvableType.forClassWithGenerics(Map.class, String.class, Person.class)) - .assertThat() - .status().isOk() - .bodyEquals(map); + .expectStatus().isOk() + .expectBody() + .map(String.class, Person.class).isEqualTo(map); } @Test @@ -106,11 +105,10 @@ public class ResponseEntityTests { .uri("/persons") .accept(TEXT_EVENT_STREAM) .exchange() - .decodeFlux(Person.class); - - result.assertThat() - .status().isOk() - .header().contentTypeEquals(TEXT_EVENT_STREAM); + .expectStatus().isOk() + .expectHeader().contentTypeEquals(TEXT_EVENT_STREAM) + .expectBody(Person.class) + .returnResult(); StepVerifier.create(result.getResponseBody()) .expectNext(new Person("N0"), new Person("N1"), new Person("N2")) @@ -124,10 +122,9 @@ public class ResponseEntityTests { public void postEntity() throws Exception { this.client.post().uri("/persons") .exchange(Mono.just(new Person("John")), Person.class) - .expectNoBody() - .assertThat() - .status().isCreated() - .header().valueEquals("location", "/persons/John"); + .expectStatus().isCreated() + .expectHeader().valueEquals("location", "/persons/John") + .expectBody().isEmpty(); } diff --git a/spring-test/src/test/java/org/springframework/test/web/reactive/server/samples/bind/ApplicationContextTests.java b/spring-test/src/test/java/org/springframework/test/web/reactive/server/samples/bind/ApplicationContextTests.java index 3bf3fc04756..c48957bdb48 100644 --- a/spring-test/src/test/java/org/springframework/test/web/reactive/server/samples/bind/ApplicationContextTests.java +++ b/spring-test/src/test/java/org/springframework/test/web/reactive/server/samples/bind/ApplicationContextTests.java @@ -51,10 +51,8 @@ public class ApplicationContextTests { public void test() throws Exception { this.client.get().uri("/test") .exchange() - .decodeEntity(String.class) - .assertThat() - .status().isOk() - .bodyEquals("It works!"); + .expectStatus().isOk() + .expectBody(String.class).value().isEqualTo("It works!"); } diff --git a/spring-test/src/test/java/org/springframework/test/web/reactive/server/samples/bind/ControllerTests.java b/spring-test/src/test/java/org/springframework/test/web/reactive/server/samples/bind/ControllerTests.java index a39a558d38b..9ab806f5362 100644 --- a/spring-test/src/test/java/org/springframework/test/web/reactive/server/samples/bind/ControllerTests.java +++ b/spring-test/src/test/java/org/springframework/test/web/reactive/server/samples/bind/ControllerTests.java @@ -43,10 +43,8 @@ public class ControllerTests { public void test() throws Exception { this.client.get().uri("/test") .exchange() - .decodeEntity(String.class) - .assertThat() - .status().isOk() - .bodyEquals("It works!"); + .expectStatus().isOk() + .expectBody(String.class).value().isEqualTo("It works!"); } diff --git a/spring-test/src/test/java/org/springframework/test/web/reactive/server/samples/bind/HttpServerTests.java b/spring-test/src/test/java/org/springframework/test/web/reactive/server/samples/bind/HttpServerTests.java index ef3de7f9364..e91ae8c0d0f 100644 --- a/spring-test/src/test/java/org/springframework/test/web/reactive/server/samples/bind/HttpServerTests.java +++ b/spring-test/src/test/java/org/springframework/test/web/reactive/server/samples/bind/HttpServerTests.java @@ -68,10 +68,8 @@ public class HttpServerTests { public void test() throws Exception { this.client.get().uri("/test") .exchange() - .decodeEntity(String.class) - .assertThat() - .status().isOk() - .bodyEquals("It works!"); + .expectStatus().isOk() + .expectBody(String.class).value().isEqualTo("It works!"); } } diff --git a/spring-test/src/test/java/org/springframework/test/web/reactive/server/samples/bind/RouterFunctionTests.java b/spring-test/src/test/java/org/springframework/test/web/reactive/server/samples/bind/RouterFunctionTests.java index 54161b4377f..3f06f33fd17 100644 --- a/spring-test/src/test/java/org/springframework/test/web/reactive/server/samples/bind/RouterFunctionTests.java +++ b/spring-test/src/test/java/org/springframework/test/web/reactive/server/samples/bind/RouterFunctionTests.java @@ -49,10 +49,8 @@ public class RouterFunctionTests { public void test() throws Exception { this.testClient.get().uri("/test") .exchange() - .decodeEntity(String.class) - .assertThat() - .status().isOk() - .bodyEquals("It works!"); + .expectStatus().isOk() + .expectBody(String.class).value().isEqualTo("It works!"); } }