Hamcrest methods in WebTestClient

Issue: SPR-16729
This commit is contained in:
Rossen Stoyanchev 2018-07-20 17:37:12 -04:00
parent 0c62d6b5da
commit 20de5003ff
11 changed files with 210 additions and 55 deletions

View File

@ -18,6 +18,7 @@ package org.springframework.test.web.reactive.server;
import java.net.URI; import java.net.URI;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.time.Duration; import java.time.Duration;
import java.time.ZonedDateTime; import java.time.ZonedDateTime;
import java.util.Arrays; import java.util.Arrays;
@ -27,8 +28,9 @@ import java.util.Optional;
import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicLong;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.function.Function; import java.util.function.Function;
import javax.xml.xpath.XPathExpressionException;
import org.hamcrest.Matcher;
import org.hamcrest.MatcherAssert;
import org.reactivestreams.Publisher; import org.reactivestreams.Publisher;
import reactor.core.publisher.Flux; 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.ClientHttpConnector;
import org.springframework.http.client.reactive.ClientHttpRequest; import org.springframework.http.client.reactive.ClientHttpRequest;
import org.springframework.lang.Nullable; import org.springframework.lang.Nullable;
import org.springframework.test.util.AssertionErrors;
import org.springframework.test.util.JsonExpectationsHelper; import org.springframework.test.util.JsonExpectationsHelper;
import org.springframework.test.util.XmlExpectationsHelper; import org.springframework.test.util.XmlExpectationsHelper;
import org.springframework.util.Assert; 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.reactive.function.client.WebClient;
import org.springframework.web.util.UriBuilder; 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}. * Default implementation of {@link WebTestClient}.
* *
@ -384,7 +383,22 @@ class DefaultWebTestClient implements WebTestClient {
@Override @Override
public <T extends S> T isEqualTo(B expected) { public <T extends S> T isEqualTo(B expected) {
this.result.assertWithDiagnostics(() -> this.result.assertWithDiagnostics(() ->
assertEquals("Response body", expected, this.result.getResponseBody())); AssertionErrors.assertEquals("Response body", expected, this.result.getResponseBody()));
return self();
}
@Override
public <T extends S> T value(Matcher<B> matcher) {
this.result.assertWithDiagnostics(() -> MatcherAssert.assertThat(this.result.getResponseBody(), matcher));
return self();
}
@Override
public <T extends S, R> T value(Function<B, R> bodyMapper, Matcher<R> matcher) {
this.result.assertWithDiagnostics(() -> {
B body = this.result.getResponseBody();
MatcherAssert.assertThat(bodyMapper.apply(body), matcher);
});
return self(); return self();
} }
@ -417,7 +431,8 @@ class DefaultWebTestClient implements WebTestClient {
public ListBodySpec<E> hasSize(int size) { public ListBodySpec<E> hasSize(int size) {
List<E> actual = getResult().getResponseBody(); List<E> actual = getResult().getResponseBody();
String message = "Response body does not contain " + size + " elements"; 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; return this;
} }
@ -427,7 +442,8 @@ class DefaultWebTestClient implements WebTestClient {
List<E> expected = Arrays.asList(elements); List<E> expected = Arrays.asList(elements);
List<E> actual = getResult().getResponseBody(); List<E> actual = getResult().getResponseBody();
String message = "Response body does not contain " + expected; 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; return this;
} }
@ -437,7 +453,8 @@ class DefaultWebTestClient implements WebTestClient {
List<E> expected = Arrays.asList(elements); List<E> expected = Arrays.asList(elements);
List<E> actual = getResult().getResponseBody(); List<E> actual = getResult().getResponseBody();
String message = "Response body should not have contained " + expected; 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; return this;
} }
@ -461,7 +478,8 @@ class DefaultWebTestClient implements WebTestClient {
@Override @Override
public EntityExchangeResult<Void> isEmpty() { public EntityExchangeResult<Void> 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); return new EntityExchangeResult<>(this.result, null);
} }
@ -506,8 +524,8 @@ class DefaultWebTestClient implements WebTestClient {
if (body == null || body.length == 0) { if (body == null || body.length == 0) {
return ""; return "";
} }
MediaType mediaType = this.result.getResponseHeaders().getContentType(); Charset charset = Optional.ofNullable(this.result.getResponseHeaders().getContentType())
Charset charset = Optional.ofNullable(mediaType).map(MimeType::getCharset).orElse(UTF_8); .map(MimeType::getCharset).orElse(StandardCharsets.UTF_8);
return new String(body, charset); return new String(body, charset);
} }

View File

@ -17,17 +17,16 @@
package org.springframework.test.web.reactive.server; package org.springframework.test.web.reactive.server;
import java.util.Arrays; 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.CacheControl;
import org.springframework.http.ContentDisposition; import org.springframework.http.ContentDisposition;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.lang.Nullable; import org.springframework.lang.Nullable;
import org.springframework.test.util.AssertionErrors;
import static org.springframework.test.util.AssertionErrors.assertEquals;
import static org.springframework.test.util.AssertionErrors.assertTrue;
import static org.springframework.test.util.AssertionErrors.fail;
/** /**
* Assertions on headers of the response. * 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 * Match the primary value of the response header with a regex.
* provided regex pattern.
* @param name the header name * @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) { 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<? super String> 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); String value = getHeaders().getFirst(name);
if (value == null) { if (value == null) {
fail(getMessage(name) + " not found"); AssertionErrors.fail(getMessage(name) + " not found");
} }
boolean match = Pattern.compile(pattern).matcher(value).matches(); return value;
String message = getMessage(name) + "=[" + value + "] does not match [" + pattern + "]";
this.exchangeResult.assertWithDiagnostics(() -> assertTrue(message, match));
return this.responseSpec;
} }
/** /**
@ -82,7 +96,7 @@ public class HeaderAssertions {
public WebTestClient.ResponseSpec exists(String name) { public WebTestClient.ResponseSpec exists(String name) {
if (!getHeaders().containsKey(name)) { if (!getHeaders().containsKey(name)) {
String message = getMessage(name) + " does not exist"; String message = getMessage(name) + " does not exist";
this.exchangeResult.assertWithDiagnostics(() -> fail(message)); this.exchangeResult.assertWithDiagnostics(() -> AssertionErrors.fail(message));
} }
return this.responseSpec; return this.responseSpec;
} }
@ -93,7 +107,7 @@ public class HeaderAssertions {
public WebTestClient.ResponseSpec doesNotExist(String name) { public WebTestClient.ResponseSpec doesNotExist(String name) {
if (getHeaders().containsKey(name)) { if (getHeaders().containsKey(name)) {
String message = getMessage(name) + " exists with value=[" + getHeaders().getFirst(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; return this.responseSpec;
} }
@ -140,7 +154,7 @@ public class HeaderAssertions {
MediaType actual = getHeaders().getContentType(); MediaType actual = getHeaders().getContentType();
String message = getMessage("Content-Type") + "=[" + actual + "] is not compatible with [" + mediaType + "]"; String message = getMessage("Content-Type") + "=[" + actual + "] is not compatible with [" + mediaType + "]";
this.exchangeResult.assertWithDiagnostics(() -> this.exchangeResult.assertWithDiagnostics(() ->
assertTrue(message, (actual != null && actual.isCompatibleWith(mediaType)))); AssertionErrors.assertTrue(message, (actual != null && actual.isCompatibleWith(mediaType))));
return this.responseSpec; return this.responseSpec;
} }
@ -175,7 +189,10 @@ public class HeaderAssertions {
} }
private WebTestClient.ResponseSpec assertHeader(String name, @Nullable Object expected, @Nullable Object actual) { 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; return this.responseSpec;
} }

View File

@ -16,6 +16,8 @@
package org.springframework.test.web.reactive.server; package org.springframework.test.web.reactive.server;
import org.hamcrest.Matcher;
import org.springframework.test.util.JsonPathExpectationsHelper; import org.springframework.test.util.JsonPathExpectationsHelper;
/** /**
@ -132,4 +134,22 @@ public class JsonPathAssertions {
return this.bodySpec; return this.bodySpec;
} }
/**
* Delegates to {@link JsonPathExpectationsHelper#assertValue(String, Matcher)}.
* @since 5.1
*/
public <T> WebTestClient.BodyContentSpec value(Matcher<T> matcher) {
this.pathHelper.assertValue(this.content, matcher);
return this.bodySpec;
}
/**
* Delegates to {@link JsonPathExpectationsHelper#assertValue(String, Matcher, Class)}.
* @since 5.1
*/
public <T> WebTestClient.BodyContentSpec value(Matcher<T> matcher, Class<T> targetType) {
this.pathHelper.assertValue(this.content, matcher, targetType);
return this.bodySpec;
}
} }

View File

@ -16,9 +16,11 @@
package org.springframework.test.web.reactive.server; 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. * Assertions on the response status.
@ -52,7 +54,7 @@ public class StatusAssertions {
*/ */
public WebTestClient.ResponseSpec isEqualTo(int status) { public WebTestClient.ResponseSpec isEqualTo(int status) {
int actual = this.exchangeResult.getStatus().value(); int actual = this.exchangeResult.getStatus().value();
this.exchangeResult.assertWithDiagnostics(() -> assertEquals("Status", status, actual)); this.exchangeResult.assertWithDiagnostics(() -> AssertionErrors.assertEquals("Status", status, actual));
return this.responseSpec; return this.responseSpec;
} }
@ -155,7 +157,7 @@ public class StatusAssertions {
public WebTestClient.ResponseSpec reasonEquals(String reason) { public WebTestClient.ResponseSpec reasonEquals(String reason) {
String actual = this.exchangeResult.getStatus().getReasonPhrase(); String actual = this.exchangeResult.getStatus().getReasonPhrase();
String message = "Response status reason"; String message = "Response status reason";
this.exchangeResult.assertWithDiagnostics(() -> assertEquals(message, reason, actual)); this.exchangeResult.assertWithDiagnostics(() -> AssertionErrors.assertEquals(message, reason, actual));
return this.responseSpec; return this.responseSpec;
} }
@ -195,17 +197,30 @@ public class StatusAssertions {
return assertSeriesAndReturn(expected); 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<Integer> 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) { private WebTestClient.ResponseSpec assertStatusAndReturn(HttpStatus expected) {
HttpStatus actual = this.exchangeResult.getStatus(); HttpStatus actual = this.exchangeResult.getStatus();
this.exchangeResult.assertWithDiagnostics(() -> assertEquals("Status", expected, actual)); this.exchangeResult.assertWithDiagnostics(() -> AssertionErrors.assertEquals("Status", expected, actual));
return this.responseSpec; return this.responseSpec;
} }
private WebTestClient.ResponseSpec assertSeriesAndReturn(HttpStatus.Series expected) { private WebTestClient.ResponseSpec assertSeriesAndReturn(HttpStatus.Series expected) {
HttpStatus status = this.exchangeResult.getStatus(); HttpStatus status = this.exchangeResult.getStatus();
this.exchangeResult.assertWithDiagnostics(() -> this.exchangeResult.assertWithDiagnostics(() -> {
assertEquals("Range for response status value " + status, expected, status.series())); String message = "Range for response status value " + status;
AssertionErrors.assertEquals(message, expected, status.series());
});
return this.responseSpec; return this.responseSpec;
} }

View File

@ -25,6 +25,7 @@ import java.util.Map;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.function.Function; import java.util.function.Function;
import org.hamcrest.Matcher;
import org.reactivestreams.Publisher; import org.reactivestreams.Publisher;
import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContext;
@ -758,6 +759,19 @@ public interface WebTestClient {
*/ */
<T extends S> T isEqualTo(B expected); <T extends S> T isEqualTo(B expected);
/**
* Assert the extracted body with a {@link Matcher}.
* @since 5.1
*/
<T extends S> T value(Matcher<B> 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 extends S, R> T value(Function<B, R> bodyMapper, Matcher<R> matcher);
/** /**
* Assert the exchange result with the given {@link Consumer}. * Assert the exchange result with the given {@link Consumer}.
*/ */
@ -851,8 +865,8 @@ public interface WebTestClient {
* formatting specifiers as defined in {@link String#format}. * formatting specifiers as defined in {@link String#format}.
* @param expression the XPath expression * @param expression the XPath expression
* @param args arguments to parameterize the expression * @param args arguments to parameterize the expression
* @see #xpath(String, Map, Object...)
* @since 5.1 * @since 5.1
* @see #xpath(String, Map, Object...)
*/ */
default XpathAssertions xpath(String expression, Object... args){ default XpathAssertions xpath(String expression, Object... args){
return xpath(expression, null, args); return xpath(expression, null, args);

View File

@ -21,6 +21,8 @@ import java.util.Map;
import java.util.Optional; import java.util.Optional;
import javax.xml.xpath.XPathExpressionException; import javax.xml.xpath.XPathExpressionException;
import org.hamcrest.Matcher;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
import org.springframework.lang.Nullable; import org.springframework.lang.Nullable;
import org.springframework.test.util.XpathExpectationsHelper; 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) { public WebTestClient.BodyContentSpec isEqualTo(String expectedValue) {
return assertWith(() -> this.xpathHelper.assertString(getContent(), getCharset(), 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) { public WebTestClient.BodyContentSpec isEqualTo(Double expectedValue) {
return assertWith(() -> this.xpathHelper.assertNumber(getContent(), getCharset(), 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) { public WebTestClient.BodyContentSpec isEqualTo(boolean expectedValue) {
return assertWith(() -> this.xpathHelper.assertBoolean(getContent(), getCharset(), 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() { public WebTestClient.BodyContentSpec exists() {
return assertWith(() -> this.xpathHelper.exists(getContent(), getCharset())); 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() { public WebTestClient.BodyContentSpec doesNotExist() {
return assertWith(() -> this.xpathHelper.doesNotExist(getContent(), getCharset())); 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) { public WebTestClient.BodyContentSpec nodeCount(int expectedCount) {
return assertWith(() -> this.xpathHelper.assertNodeCount(getContent(), getCharset(), expectedCount)); return assertWith(() -> this.xpathHelper.assertNodeCount(getContent(), getCharset(), expectedCount));
} }
/**
* Delegates to {@link XpathExpectationsHelper#assertString(byte[], String, Matcher)}.
*/
public WebTestClient.BodyContentSpec string(Matcher<? super String> matcher){
return assertWith(() -> this.xpathHelper.assertString(getContent(), getCharset(), matcher));
}
/**
* Delegates to {@link XpathExpectationsHelper#assertNumber(byte[], String, Matcher)}.
*/
public WebTestClient.BodyContentSpec number(Matcher<? super Double> matcher){
return assertWith(() -> this.xpathHelper.assertNumber(getContent(), getCharset(), matcher));
}
/**
* Delegates to {@link XpathExpectationsHelper#assertNodeCount(byte[], String, Matcher)}.
*/
public WebTestClient.BodyContentSpec nodeCount(Matcher<Integer> matcher){
return assertWith(() -> this.xpathHelper.assertNodeCount(getContent(), getCharset(), matcher));
}
private WebTestClient.BodyContentSpec assertWith(CheckedExceptionTask task) { private WebTestClient.BodyContentSpec assertWith(CheckedExceptionTask task) {
try { try {

View File

@ -30,6 +30,7 @@ import org.springframework.http.MediaType;
import org.springframework.mock.http.client.reactive.MockClientHttpRequest; import org.springframework.mock.http.client.reactive.MockClientHttpRequest;
import org.springframework.mock.http.client.reactive.MockClientHttpResponse; import org.springframework.mock.http.client.reactive.MockClientHttpResponse;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*; import static org.junit.Assert.*;
import static org.mockito.Mockito.*; 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 @Test
public void exists() { public void exists() {
HttpHeaders headers = new HttpHeaders(); HttpHeaders headers = new HttpHeaders();

View File

@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with 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.MockClientHttpRequest;
import org.springframework.mock.http.client.reactive.MockClientHttpResponse; import org.springframework.mock.http.client.reactive.MockClientHttpResponse;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*; import static org.junit.Assert.*;
import static org.mockito.Mockito.*; 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) { private StatusAssertions statusAssertions(HttpStatus status) {
MockClientHttpRequest request = new MockClientHttpRequest(HttpMethod.GET, URI.create("/")); MockClientHttpRequest request = new MockClientHttpRequest(HttpMethod.GET, URI.create("/"));

View File

@ -31,6 +31,8 @@ import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import static org.hamcrest.Matchers.*;
/** /**
* Samples of tests using {@link WebTestClient} with serialized JSON content. * Samples of tests using {@link WebTestClient} with serialized JSON content.
* *
@ -64,16 +66,14 @@ public class JsonContentTests {
.jsonPath("$[2].name").isEqualTo("John"); .jsonPath("$[2].name").isEqualTo("John");
} }
@Test // https://stackoverflow.com/questions/49149376/webtestclient-check-that-jsonpath-contains-sub-string @Test
public void jsonPathContainsSubstringViaRegex() { public void jsonPathMatches() {
this.client.get().uri("/persons/John") this.client.get().uri("/persons/John")
.accept(MediaType.APPLICATION_JSON_UTF8) .accept(MediaType.APPLICATION_JSON_UTF8)
.exchange() .exchange()
.expectStatus().isOk() .expectStatus().isOk()
.expectBody() .expectBody()
// The following determines if at least one person is returned with a .jsonPath("$.name").value(containsString("oh"));
// name containing "oh", and "John" matches that.
.jsonPath("$[?(@.name =~ /.*oh.*/)].name").hasJsonPath();
} }
@Test @Test

View File

@ -38,11 +38,10 @@ import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import static java.time.Duration.ofMillis; import static java.time.Duration.*;
import static org.hamcrest.CoreMatchers.endsWith; import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.*;
import static org.junit.Assert.assertThat; import static org.springframework.http.MediaType.*;
import static org.springframework.http.MediaType.TEXT_EVENT_STREAM;
/** /**
* Annotated controllers accepting and returning typed Objects. * Annotated controllers accepting and returning typed Objects.
@ -67,6 +66,15 @@ public class ResponseEntityTests {
.expectBody(Person.class).isEqualTo(new Person("John")); .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 @Test
public void entityWithConsumer() { public void entityWithConsumer() {
this.client.get().uri("/John") this.client.get().uri("/John")

View File

@ -38,6 +38,8 @@ import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import static org.hamcrest.Matchers.*;
/** /**
* Samples of tests using {@link WebTestClient} with XML content. * Samples of tests using {@link WebTestClient} with XML content.
* *
@ -83,6 +85,16 @@ public class XmlContentTests {
.xpath("/persons/person[3]/name").isEqualTo("John"); .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 @Test
public void xpathContainsSubstringViaRegex() { public void xpathContainsSubstringViaRegex() {
this.client.get().uri("/persons/John") this.client.get().uri("/persons/John")