From 20de5003ffbc8d8ffdd442f9db46195db46a6b4d Mon Sep 17 00:00:00 2001 From: Rossen Stoyanchev Date: Fri, 20 Jul 2018 17:37:12 -0400 Subject: [PATCH] Hamcrest methods in WebTestClient Issue: SPR-16729 --- .../reactive/server/DefaultWebTestClient.java | 42 ++++++++++----- .../web/reactive/server/HeaderAssertions.java | 51 ++++++++++++------- .../reactive/server/JsonPathAssertions.java | 20 ++++++++ .../web/reactive/server/StatusAssertions.java | 29 ++++++++--- .../web/reactive/server/WebTestClient.java | 16 +++++- .../web/reactive/server/XpathAssertions.java | 37 +++++++++++--- .../reactive/server/HeaderAssertionTests.java | 10 ++++ .../reactive/server/StatusAssertionTests.java | 20 +++++++- .../server/samples/JsonContentTests.java | 10 ++-- .../server/samples/ResponseEntityTests.java | 18 +++++-- .../server/samples/XmlContentTests.java | 12 +++++ 11 files changed, 210 insertions(+), 55 deletions(-) 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 e5bb31efaae..87dbeec8514 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 @@ -18,6 +18,7 @@ package org.springframework.test.web.reactive.server; import java.net.URI; import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; import java.time.Duration; import java.time.ZonedDateTime; import java.util.Arrays; @@ -27,8 +28,9 @@ import java.util.Optional; import java.util.concurrent.atomic.AtomicLong; import java.util.function.Consumer; import java.util.function.Function; -import javax.xml.xpath.XPathExpressionException; +import org.hamcrest.Matcher; +import org.hamcrest.MatcherAssert; import org.reactivestreams.Publisher; import reactor.core.publisher.Flux; @@ -40,6 +42,7 @@ import org.springframework.http.MediaType; 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.JsonExpectationsHelper; import org.springframework.test.util.XmlExpectationsHelper; import org.springframework.util.Assert; @@ -50,10 +53,6 @@ import org.springframework.web.reactive.function.client.ClientResponse; import org.springframework.web.reactive.function.client.WebClient; import org.springframework.web.util.UriBuilder; -import static java.nio.charset.StandardCharsets.UTF_8; -import static org.springframework.test.util.AssertionErrors.assertEquals; -import static org.springframework.test.util.AssertionErrors.assertTrue; - /** * Default implementation of {@link WebTestClient}. * @@ -384,7 +383,22 @@ class DefaultWebTestClient implements WebTestClient { @Override public T isEqualTo(B expected) { this.result.assertWithDiagnostics(() -> - assertEquals("Response body", expected, this.result.getResponseBody())); + AssertionErrors.assertEquals("Response body", expected, this.result.getResponseBody())); + return self(); + } + + @Override + public T value(Matcher matcher) { + this.result.assertWithDiagnostics(() -> MatcherAssert.assertThat(this.result.getResponseBody(), matcher)); + return self(); + } + + @Override + public T value(Function bodyMapper, Matcher matcher) { + this.result.assertWithDiagnostics(() -> { + B body = this.result.getResponseBody(); + MatcherAssert.assertThat(bodyMapper.apply(body), matcher); + }); return self(); } @@ -417,7 +431,8 @@ class DefaultWebTestClient implements WebTestClient { public ListBodySpec hasSize(int size) { List actual = getResult().getResponseBody(); String message = "Response body does not contain " + size + " elements"; - getResult().assertWithDiagnostics(() -> assertEquals(message, size, (actual != null ? actual.size() : 0))); + getResult().assertWithDiagnostics(() -> + AssertionErrors.assertEquals(message, size, (actual != null ? actual.size() : 0))); return this; } @@ -427,7 +442,8 @@ class DefaultWebTestClient implements WebTestClient { List expected = Arrays.asList(elements); List actual = getResult().getResponseBody(); String message = "Response body does not contain " + expected; - getResult().assertWithDiagnostics(() -> assertTrue(message, (actual != null && actual.containsAll(expected)))); + getResult().assertWithDiagnostics(() -> + AssertionErrors.assertTrue(message, (actual != null && actual.containsAll(expected)))); return this; } @@ -437,7 +453,8 @@ class DefaultWebTestClient implements WebTestClient { List expected = Arrays.asList(elements); List actual = getResult().getResponseBody(); String message = "Response body should not have contained " + expected; - getResult().assertWithDiagnostics(() -> assertTrue(message, (actual == null || !actual.containsAll(expected)))); + getResult().assertWithDiagnostics(() -> + AssertionErrors.assertTrue(message, (actual == null || !actual.containsAll(expected)))); return this; } @@ -461,7 +478,8 @@ class DefaultWebTestClient implements WebTestClient { @Override public EntityExchangeResult isEmpty() { - this.result.assertWithDiagnostics(() -> assertTrue("Expected empty body", this.isEmpty)); + this.result.assertWithDiagnostics(() -> + AssertionErrors.assertTrue("Expected empty body", this.isEmpty)); return new EntityExchangeResult<>(this.result, null); } @@ -506,8 +524,8 @@ class DefaultWebTestClient implements WebTestClient { if (body == null || body.length == 0) { return ""; } - MediaType mediaType = this.result.getResponseHeaders().getContentType(); - Charset charset = Optional.ofNullable(mediaType).map(MimeType::getCharset).orElse(UTF_8); + Charset charset = Optional.ofNullable(this.result.getResponseHeaders().getContentType()) + .map(MimeType::getCharset).orElse(StandardCharsets.UTF_8); return new String(body, charset); } 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 e3d43740561..98ab8e893f1 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 @@ -17,17 +17,16 @@ package org.springframework.test.web.reactive.server; import java.util.Arrays; -import java.util.regex.Pattern; + +import org.hamcrest.Matcher; +import org.hamcrest.MatcherAssert; import org.springframework.http.CacheControl; import org.springframework.http.ContentDisposition; import org.springframework.http.HttpHeaders; import org.springframework.http.MediaType; import org.springframework.lang.Nullable; - -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 org.springframework.test.util.AssertionErrors; /** * Assertions on headers of the response. @@ -59,20 +58,35 @@ public class HeaderAssertions { } /** - * Expect a header with the given name whose first value matches the - * provided regex pattern. + * Match the primary value of the response header with a regex. * @param name the header name - * @param pattern the String pattern to pass to {@link Pattern#compile(String)} + * @param pattern the regex pattern */ public WebTestClient.ResponseSpec valueMatches(String name, String pattern) { + String value = getRequiredValue(name); + String message = getMessage(name) + "=[" + value + "] does not match [" + pattern + "]"; + this.exchangeResult.assertWithDiagnostics(() -> AssertionErrors.assertTrue(message, value.matches(pattern))); + return this.responseSpec; + } + + /** + * Assert the primary value of the response header with a {@link Matcher}. + * @param name the header name + * @param matcher the matcher to sue + * @since 5.1 + */ + public WebTestClient.ResponseSpec value(String name, Matcher matcher) { + String value = getRequiredValue(name); + this.exchangeResult.assertWithDiagnostics(() -> MatcherAssert.assertThat(value, matcher)); + return this.responseSpec; + } + + private String getRequiredValue(String name) { String value = getHeaders().getFirst(name); if (value == null) { - fail(getMessage(name) + " not found"); + AssertionErrors.fail(getMessage(name) + " not found"); } - boolean match = Pattern.compile(pattern).matcher(value).matches(); - String message = getMessage(name) + "=[" + value + "] does not match [" + pattern + "]"; - this.exchangeResult.assertWithDiagnostics(() -> assertTrue(message, match)); - return this.responseSpec; + return value; } /** @@ -82,7 +96,7 @@ public class HeaderAssertions { public WebTestClient.ResponseSpec exists(String name) { if (!getHeaders().containsKey(name)) { String message = getMessage(name) + " does not exist"; - this.exchangeResult.assertWithDiagnostics(() -> fail(message)); + this.exchangeResult.assertWithDiagnostics(() -> AssertionErrors.fail(message)); } return this.responseSpec; } @@ -93,7 +107,7 @@ public class HeaderAssertions { public WebTestClient.ResponseSpec doesNotExist(String name) { if (getHeaders().containsKey(name)) { String message = getMessage(name) + " exists with value=[" + getHeaders().getFirst(name) + "]"; - this.exchangeResult.assertWithDiagnostics(() -> fail(message)); + this.exchangeResult.assertWithDiagnostics(() -> AssertionErrors.fail(message)); } return this.responseSpec; } @@ -140,7 +154,7 @@ public class HeaderAssertions { MediaType actual = getHeaders().getContentType(); String message = getMessage("Content-Type") + "=[" + actual + "] is not compatible with [" + mediaType + "]"; this.exchangeResult.assertWithDiagnostics(() -> - assertTrue(message, (actual != null && actual.isCompatibleWith(mediaType)))); + AssertionErrors.assertTrue(message, (actual != null && actual.isCompatibleWith(mediaType)))); return this.responseSpec; } @@ -175,7 +189,10 @@ public class HeaderAssertions { } private WebTestClient.ResponseSpec assertHeader(String name, @Nullable Object expected, @Nullable Object actual) { - this.exchangeResult.assertWithDiagnostics(() -> assertEquals(getMessage(name), expected, actual)); + this.exchangeResult.assertWithDiagnostics(() -> { + String message = getMessage(name); + AssertionErrors.assertEquals(message, expected, actual); + }); return this.responseSpec; } diff --git a/spring-test/src/main/java/org/springframework/test/web/reactive/server/JsonPathAssertions.java b/spring-test/src/main/java/org/springframework/test/web/reactive/server/JsonPathAssertions.java index 055f9154fba..7222bec461d 100644 --- a/spring-test/src/main/java/org/springframework/test/web/reactive/server/JsonPathAssertions.java +++ b/spring-test/src/main/java/org/springframework/test/web/reactive/server/JsonPathAssertions.java @@ -16,6 +16,8 @@ package org.springframework.test.web.reactive.server; +import org.hamcrest.Matcher; + import org.springframework.test.util.JsonPathExpectationsHelper; /** @@ -132,4 +134,22 @@ public class JsonPathAssertions { return this.bodySpec; } + /** + * Delegates to {@link JsonPathExpectationsHelper#assertValue(String, Matcher)}. + * @since 5.1 + */ + public WebTestClient.BodyContentSpec value(Matcher matcher) { + this.pathHelper.assertValue(this.content, matcher); + return this.bodySpec; + } + + /** + * Delegates to {@link JsonPathExpectationsHelper#assertValue(String, Matcher, Class)}. + * @since 5.1 + */ + public WebTestClient.BodyContentSpec value(Matcher matcher, Class targetType) { + this.pathHelper.assertValue(this.content, matcher, targetType); + return this.bodySpec; + } + } 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 6e13ad34933..d59f33a5cd0 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 @@ -16,9 +16,11 @@ package org.springframework.test.web.reactive.server; -import org.springframework.http.HttpStatus; +import org.hamcrest.Matcher; +import org.hamcrest.MatcherAssert; -import static org.springframework.test.util.AssertionErrors.assertEquals; +import org.springframework.http.HttpStatus; +import org.springframework.test.util.AssertionErrors; /** * Assertions on the response status. @@ -52,7 +54,7 @@ public class StatusAssertions { */ public WebTestClient.ResponseSpec isEqualTo(int status) { int actual = this.exchangeResult.getStatus().value(); - this.exchangeResult.assertWithDiagnostics(() -> assertEquals("Status", status, actual)); + this.exchangeResult.assertWithDiagnostics(() -> AssertionErrors.assertEquals("Status", status, actual)); return this.responseSpec; } @@ -155,7 +157,7 @@ public class StatusAssertions { public WebTestClient.ResponseSpec reasonEquals(String reason) { String actual = this.exchangeResult.getStatus().getReasonPhrase(); String message = "Response status reason"; - this.exchangeResult.assertWithDiagnostics(() -> assertEquals(message, reason, actual)); + this.exchangeResult.assertWithDiagnostics(() -> AssertionErrors.assertEquals(message, reason, actual)); return this.responseSpec; } @@ -195,17 +197,30 @@ public class StatusAssertions { return assertSeriesAndReturn(expected); } + /** + * Match the response status value with a Hamcrest matcher. + * @param matcher the matcher to use + * @since 5.1 + */ + public WebTestClient.ResponseSpec value(Matcher matcher) { + int value = this.exchangeResult.getStatus().value(); + this.exchangeResult.assertWithDiagnostics(() -> MatcherAssert.assertThat("Response status", value, matcher)); + return this.responseSpec; + } + private WebTestClient.ResponseSpec assertStatusAndReturn(HttpStatus expected) { HttpStatus actual = this.exchangeResult.getStatus(); - this.exchangeResult.assertWithDiagnostics(() -> assertEquals("Status", expected, actual)); + this.exchangeResult.assertWithDiagnostics(() -> AssertionErrors.assertEquals("Status", expected, actual)); return this.responseSpec; } private WebTestClient.ResponseSpec assertSeriesAndReturn(HttpStatus.Series expected) { HttpStatus status = this.exchangeResult.getStatus(); - this.exchangeResult.assertWithDiagnostics(() -> - assertEquals("Range for response status value " + status, expected, status.series())); + this.exchangeResult.assertWithDiagnostics(() -> { + String message = "Range for response status value " + status; + AssertionErrors.assertEquals(message, expected, status.series()); + }); 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 90502e7ed5e..681721485be 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 @@ -25,6 +25,7 @@ import java.util.Map; import java.util.function.Consumer; import java.util.function.Function; +import org.hamcrest.Matcher; import org.reactivestreams.Publisher; import org.springframework.context.ApplicationContext; @@ -758,6 +759,19 @@ public interface WebTestClient { */ T isEqualTo(B expected); + /** + * Assert the extracted body with a {@link Matcher}. + * @since 5.1 + */ + T value(Matcher matcher); + + /** + * Transform the extracted the body with a function, e.g. extracting a + * property, and assert the mapped value with a {@link Matcher}. + * @since 5.1 + */ + T value(Function bodyMapper, Matcher matcher); + /** * Assert the exchange result with the given {@link Consumer}. */ @@ -851,8 +865,8 @@ public interface WebTestClient { * formatting specifiers as defined in {@link String#format}. * @param expression the XPath expression * @param args arguments to parameterize the expression - * @see #xpath(String, Map, Object...) * @since 5.1 + * @see #xpath(String, Map, Object...) */ default XpathAssertions xpath(String expression, Object... args){ return xpath(expression, null, args); diff --git a/spring-test/src/main/java/org/springframework/test/web/reactive/server/XpathAssertions.java b/spring-test/src/main/java/org/springframework/test/web/reactive/server/XpathAssertions.java index a882d9ddc2c..91b62e9320e 100644 --- a/spring-test/src/main/java/org/springframework/test/web/reactive/server/XpathAssertions.java +++ b/spring-test/src/main/java/org/springframework/test/web/reactive/server/XpathAssertions.java @@ -21,6 +21,8 @@ import java.util.Map; import java.util.Optional; import javax.xml.xpath.XPathExpressionException; +import org.hamcrest.Matcher; + import org.springframework.http.HttpHeaders; import org.springframework.lang.Nullable; import org.springframework.test.util.XpathExpectationsHelper; @@ -62,47 +64,68 @@ public class XpathAssertions { /** - * Delegates to {@link XpathExpectationsHelper#assertString(byte[], String, String)} + * Delegates to {@link XpathExpectationsHelper#assertString(byte[], String, String)}. */ public WebTestClient.BodyContentSpec isEqualTo(String expectedValue) { return assertWith(() -> this.xpathHelper.assertString(getContent(), getCharset(), expectedValue)); } /** - * Delegates to {@link XpathExpectationsHelper#assertNumber(byte[], String, Double)} + * Delegates to {@link XpathExpectationsHelper#assertNumber(byte[], String, Double)}. */ public WebTestClient.BodyContentSpec isEqualTo(Double expectedValue) { return assertWith(() -> this.xpathHelper.assertNumber(getContent(), getCharset(), expectedValue)); } /** - * Delegates to {@link XpathExpectationsHelper#assertBoolean(byte[], String, boolean)} + * Delegates to {@link XpathExpectationsHelper#assertBoolean(byte[], String, boolean)}. */ public WebTestClient.BodyContentSpec isEqualTo(boolean expectedValue) { return assertWith(() -> this.xpathHelper.assertBoolean(getContent(), getCharset(), expectedValue)); } /** - * Delegates to {@link XpathExpectationsHelper#exists(byte[], String)} + * Delegates to {@link XpathExpectationsHelper#exists(byte[], String)}. */ public WebTestClient.BodyContentSpec exists() { return assertWith(() -> this.xpathHelper.exists(getContent(), getCharset())); } /** - * Delegates to {@link XpathExpectationsHelper#doesNotExist(byte[], String)} + * Delegates to {@link XpathExpectationsHelper#doesNotExist(byte[], String)}. */ public WebTestClient.BodyContentSpec doesNotExist() { return assertWith(() -> this.xpathHelper.doesNotExist(getContent(), getCharset())); } /** - * Delegates to {@link XpathExpectationsHelper[#assertNodeCount(byte[], String, int)} + * Delegates to {@link XpathExpectationsHelper#assertNodeCount(byte[], String, int)}. */ public WebTestClient.BodyContentSpec nodeCount(int expectedCount) { return assertWith(() -> this.xpathHelper.assertNodeCount(getContent(), getCharset(), expectedCount)); } + /** + * Delegates to {@link XpathExpectationsHelper#assertString(byte[], String, Matcher)}. + */ + public WebTestClient.BodyContentSpec string(Matcher matcher){ + return assertWith(() -> this.xpathHelper.assertString(getContent(), getCharset(), matcher)); + } + + /** + * Delegates to {@link XpathExpectationsHelper#assertNumber(byte[], String, Matcher)}. + */ + public WebTestClient.BodyContentSpec number(Matcher matcher){ + return assertWith(() -> this.xpathHelper.assertNumber(getContent(), getCharset(), matcher)); + } + + /** + * Delegates to {@link XpathExpectationsHelper#assertNodeCount(byte[], String, Matcher)}. + */ + public WebTestClient.BodyContentSpec nodeCount(Matcher matcher){ + return assertWith(() -> this.xpathHelper.assertNodeCount(getContent(), getCharset(), matcher)); + } + private WebTestClient.BodyContentSpec assertWith(CheckedExceptionTask task) { try { @@ -139,4 +162,4 @@ public class XpathAssertions { void run() throws Exception; } -} \ No newline at end of file +} diff --git a/spring-test/src/test/java/org/springframework/test/web/reactive/server/HeaderAssertionTests.java b/spring-test/src/test/java/org/springframework/test/web/reactive/server/HeaderAssertionTests.java index b920fbbcd6b..8ac506e6d6e 100644 --- a/spring-test/src/test/java/org/springframework/test/web/reactive/server/HeaderAssertionTests.java +++ b/spring-test/src/test/java/org/springframework/test/web/reactive/server/HeaderAssertionTests.java @@ -30,6 +30,7 @@ import org.springframework.http.MediaType; import org.springframework.mock.http.client.reactive.MockClientHttpRequest; import org.springframework.mock.http.client.reactive.MockClientHttpResponse; +import static org.hamcrest.CoreMatchers.*; import static org.junit.Assert.*; import static org.mockito.Mockito.*; @@ -125,6 +126,15 @@ public class HeaderAssertionTests { } } + @Test + public void valueMatcher() { + HttpHeaders headers = new HttpHeaders(); + headers.add("foo", "bar"); + HeaderAssertions assertions = headerAssertions(headers); + + assertions.value("foo", containsString("a")); + } + @Test public void exists() { HttpHeaders headers = new HttpHeaders(); diff --git a/spring-test/src/test/java/org/springframework/test/web/reactive/server/StatusAssertionTests.java b/spring-test/src/test/java/org/springframework/test/web/reactive/server/StatusAssertionTests.java index ccd69c06191..a570580cd65 100644 --- a/spring-test/src/test/java/org/springframework/test/web/reactive/server/StatusAssertionTests.java +++ b/spring-test/src/test/java/org/springframework/test/web/reactive/server/StatusAssertionTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2017 the original author or authors. + * Copyright 2002-2018 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. @@ -26,6 +26,7 @@ import org.springframework.http.HttpStatus; import org.springframework.mock.http.client.reactive.MockClientHttpRequest; import org.springframework.mock.http.client.reactive.MockClientHttpResponse; +import static org.hamcrest.Matchers.*; import static org.junit.Assert.*; import static org.mockito.Mockito.*; @@ -158,6 +159,23 @@ public class StatusAssertionTests { } } + @Test + public void matches() { + StatusAssertions assertions = statusAssertions(HttpStatus.CONFLICT); + + // Success + assertions.value(equalTo(409)); + assertions.value(greaterThan(400)); + + try { + assertions.value(equalTo(200)); + fail("Wrong status expected"); + } + catch (AssertionError error) { + // Expected + } + } + private StatusAssertions statusAssertions(HttpStatus status) { MockClientHttpRequest request = new MockClientHttpRequest(HttpMethod.GET, URI.create("/")); diff --git a/spring-test/src/test/java/org/springframework/test/web/reactive/server/samples/JsonContentTests.java b/spring-test/src/test/java/org/springframework/test/web/reactive/server/samples/JsonContentTests.java index 03f1d8dec34..cc5a4d6bd2c 100644 --- a/spring-test/src/test/java/org/springframework/test/web/reactive/server/samples/JsonContentTests.java +++ b/spring-test/src/test/java/org/springframework/test/web/reactive/server/samples/JsonContentTests.java @@ -31,6 +31,8 @@ import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; +import static org.hamcrest.Matchers.*; + /** * Samples of tests using {@link WebTestClient} with serialized JSON content. * @@ -64,16 +66,14 @@ public class JsonContentTests { .jsonPath("$[2].name").isEqualTo("John"); } - @Test // https://stackoverflow.com/questions/49149376/webtestclient-check-that-jsonpath-contains-sub-string - public void jsonPathContainsSubstringViaRegex() { + @Test + public void jsonPathMatches() { this.client.get().uri("/persons/John") .accept(MediaType.APPLICATION_JSON_UTF8) .exchange() .expectStatus().isOk() .expectBody() - // The following determines if at least one person is returned with a - // name containing "oh", and "John" matches that. - .jsonPath("$[?(@.name =~ /.*oh.*/)].name").hasJsonPath(); + .jsonPath("$.name").value(containsString("oh")); } @Test 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 7048c2552a5..ad07f3c9561 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 @@ -38,11 +38,10 @@ import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; -import static java.time.Duration.ofMillis; -import static org.hamcrest.CoreMatchers.endsWith; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertThat; -import static org.springframework.http.MediaType.TEXT_EVENT_STREAM; +import static java.time.Duration.*; +import static org.hamcrest.CoreMatchers.*; +import static org.junit.Assert.*; +import static org.springframework.http.MediaType.*; /** * Annotated controllers accepting and returning typed Objects. @@ -67,6 +66,15 @@ public class ResponseEntityTests { .expectBody(Person.class).isEqualTo(new Person("John")); } + @Test + public void entityMatcher() { + this.client.get().uri("/John") + .exchange() + .expectStatus().isOk() + .expectHeader().contentType(MediaType.APPLICATION_JSON_UTF8) + .expectBody(Person.class).value(Person::getName, startsWith("Joh")); + } + @Test public void entityWithConsumer() { this.client.get().uri("/John") diff --git a/spring-test/src/test/java/org/springframework/test/web/reactive/server/samples/XmlContentTests.java b/spring-test/src/test/java/org/springframework/test/web/reactive/server/samples/XmlContentTests.java index 99ea60afba1..c4e421ba43d 100644 --- a/spring-test/src/test/java/org/springframework/test/web/reactive/server/samples/XmlContentTests.java +++ b/spring-test/src/test/java/org/springframework/test/web/reactive/server/samples/XmlContentTests.java @@ -38,6 +38,8 @@ import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; +import static org.hamcrest.Matchers.*; + /** * Samples of tests using {@link WebTestClient} with XML content. * @@ -83,6 +85,16 @@ public class XmlContentTests { .xpath("/persons/person[3]/name").isEqualTo("John"); } + @Test + public void xpathMatches() { + this.client.get().uri("/persons") + .accept(MediaType.APPLICATION_XML) + .exchange() + .expectStatus().isOk() + .expectBody() + .xpath("//person/name").string(startsWith("J")); + } + @Test public void xpathContainsSubstringViaRegex() { this.client.get().uri("/persons/John")