Polish soft assertion support for WebTestClient
See gh-26969
This commit is contained in:
@@ -21,7 +21,6 @@ import java.nio.charset.Charset;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.time.Duration;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
@@ -45,6 +44,7 @@ import org.springframework.http.client.reactive.ClientHttpConnector;
|
||||
import org.springframework.http.client.reactive.ClientHttpRequest;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.test.util.AssertionErrors;
|
||||
import org.springframework.test.util.ExceptionCollector;
|
||||
import org.springframework.test.util.JsonExpectationsHelper;
|
||||
import org.springframework.test.util.XmlExpectationsHelper;
|
||||
import org.springframework.util.Assert;
|
||||
@@ -64,6 +64,8 @@ import org.springframework.web.util.UriBuilderFactory;
|
||||
* Default implementation of {@link WebTestClient}.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @author Sam Brannen
|
||||
* @author Michał Rowicki
|
||||
* @since 5.0
|
||||
*/
|
||||
class DefaultWebTestClient implements WebTestClient {
|
||||
@@ -510,19 +512,25 @@ class DefaultWebTestClient implements WebTestClient {
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseSpec expectAllSoftly(ResponseSpecMatcher... asserts) {
|
||||
List<String> failedMessages = new ArrayList<>();
|
||||
for (int i = 0; i < asserts.length; i++) {
|
||||
ResponseSpecMatcher anAssert = asserts[i];
|
||||
try {
|
||||
anAssert.accept(this);
|
||||
}
|
||||
catch (AssertionError assertionException) {
|
||||
failedMessages.add("[" + i + "] " + assertionException.getMessage());
|
||||
}
|
||||
public ResponseSpec expectAll(ResponseSpecConsumer... consumers) {
|
||||
ExceptionCollector exceptionCollector = new ExceptionCollector();
|
||||
for (ResponseSpecConsumer consumer : consumers) {
|
||||
exceptionCollector.execute(() -> consumer.accept(this));
|
||||
}
|
||||
if (!failedMessages.isEmpty()) {
|
||||
throw new AssertionError(String.join("\n", failedMessages));
|
||||
try {
|
||||
exceptionCollector.assertEmpty();
|
||||
}
|
||||
catch (RuntimeException ex) {
|
||||
throw ex;
|
||||
}
|
||||
catch (Exception ex) {
|
||||
// In theory, a ResponseSpecConsumer should never throw an Exception
|
||||
// that is not a RuntimeException, but since ExceptionCollector may
|
||||
// throw a checked Exception, we handle this to appease the compiler
|
||||
// and in case someone uses a "sneaky throws" technique.
|
||||
AssertionError assertionError = new AssertionError(ex.getMessage());
|
||||
assertionError.initCause(ex);
|
||||
throw assertionError;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -86,6 +86,8 @@ import org.springframework.web.util.UriBuilderFactory;
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @author Brian Clozel
|
||||
* @author Sam Brannen
|
||||
* @author Michał Rowicki
|
||||
* @since 5.0
|
||||
* @see StatusAssertions
|
||||
* @see HeaderAssertions
|
||||
@@ -781,6 +783,34 @@ public interface WebTestClient {
|
||||
*/
|
||||
interface ResponseSpec {
|
||||
|
||||
/**
|
||||
* 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,
|
||||
* it will be rethrown.
|
||||
* <p>If multiple exceptions are thrown, this method will throw an
|
||||
* {@link AssertionError} whose error message is a summary of all of the
|
||||
* exceptions. In addition, each exception will be added as a
|
||||
* {@linkplain Throwable#addSuppressed(Throwable) suppressed exception} to
|
||||
* the {@code AssertionError}.
|
||||
* <p>This feature is similar to the {@code SoftAssertions} support in
|
||||
* AssertJ and the {@code assertAll()} support in JUnit Jupiter.
|
||||
*
|
||||
* <h4>Example</h4>
|
||||
* <pre class="code">
|
||||
* webTestClient.get().uri("/hello").exchange()
|
||||
* .expectAll(
|
||||
* responseSpec -> responseSpec.expectStatus().isOk(),
|
||||
* responseSpec -> responseSpec.expectBody(String.class).isEqualTo("Hello, World!")
|
||||
* );
|
||||
* </pre>
|
||||
* @param consumers the list of {@code ResponseSpec} consumers
|
||||
* @since 5.3.10
|
||||
*/
|
||||
ResponseSpec expectAll(ResponseSpecConsumer... consumers);
|
||||
|
||||
/**
|
||||
* Assertions on the response status.
|
||||
*/
|
||||
@@ -847,9 +877,14 @@ public interface WebTestClient {
|
||||
<T> FluxExchangeResult<T> returnResult(ParameterizedTypeReference<T> elementTypeRef);
|
||||
|
||||
/**
|
||||
* Array of assertions to test together a.k.a. soft assertions.
|
||||
* {@link Consumer} of a {@link ResponseSpec}.
|
||||
* @since 5.3.10
|
||||
* @see ResponseSpec#expectAll(ResponseSpecConsumer...)
|
||||
*/
|
||||
ResponseSpec expectAllSoftly(ResponseSpecMatcher... asserts);
|
||||
@FunctionalInterface
|
||||
interface ResponseSpecConsumer extends Consumer<ResponseSpec> {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -1011,5 +1046,4 @@ public interface WebTestClient {
|
||||
EntityExchangeResult<byte[]> returnResult();
|
||||
}
|
||||
|
||||
interface ResponseSpecMatcher extends Consumer<ResponseSpec> {}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user