Leaving out hamcrest for now, to address more broadly.

Issue: SPR-16741
This commit is contained in:
Rossen Stoyanchev
2018-07-20 10:36:57 -04:00
parent 2734f01067
commit 0c62d6b5da
5 changed files with 117 additions and 191 deletions

View File

@@ -497,13 +497,8 @@ class DefaultWebTestClient implements WebTestClient {
}
@Override
public XpathAssertions xpath(String expression, Map<String, String> namespaces, Object... args) {
try {
return new XpathAssertions(this, expression, namespaces, args);
}
catch (XPathExpressionException ex) {
throw new AssertionError("XML parsing error", ex);
}
public XpathAssertions xpath(String expression, @Nullable Map<String, String> namespaces, Object... args) {
return new XpathAssertions(this, expression, namespaces, args);
}
private String getBodyAsString() {

View File

@@ -36,6 +36,7 @@ import org.springframework.http.MediaType;
import org.springframework.http.client.reactive.ClientHttpConnector;
import org.springframework.http.client.reactive.ClientHttpRequest;
import org.springframework.http.codec.ServerCodecConfigurer;
import org.springframework.lang.Nullable;
import org.springframework.util.MultiValueMap;
import org.springframework.validation.Validator;
import org.springframework.web.reactive.accept.RequestedContentTypeResolverBuilder;
@@ -820,10 +821,15 @@ public interface WebTestClient {
BodyContentSpec json(String expectedJson);
/**
* Parse the expected and actual response content as XML and perform a
* comparison verifying the same structure.
* Parse expected and actual response content as XML and assert that
* the two are "similar", i.e. they contain the same elements and
* attributes regardless of order.
* <p>Use of this method requires the
* <a href="https://github.com/xmlunit/xmlunit">XMLUnit</a> library on
* the classpath.
* @param expectedXml the expected JSON content.
* @since 5.1
* @see org.springframework.test.util.XmlExpectationsHelper#assertXmlEqual(String, String)
*/
BodyContentSpec xml(String expectedXml);
@@ -839,11 +845,11 @@ public interface WebTestClient {
JsonPathAssertions jsonPath(String expression, Object... args);
/**
* Access to response body assertions using an XPath expression to inspect a specific
* subset of the body.
* Access to response body assertions using an XPath expression to
* inspect a specific subset of the body.
* <p>The XPath expression can be a parameterized string using
* 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
* @see #xpath(String, Map, Object...)
* @since 5.1
@@ -853,16 +859,16 @@ public interface WebTestClient {
}
/**
* Access to response body assertions with specific namespaces using an XPath
* expression to inspect a specific subset of the body.
* Access to response body assertions with specific namespaces using an
* XPath expression to inspect a specific subset of the body.
* <p>The XPath expression can be a parameterized string using
* formatting specifiers as defined in {@link String#format}.
* @param expression The XPath expression
* @param namespaces The namespaces
* @param expression the XPath expression
* @param namespaces namespaces to use
* @param args arguments to parameterize the expression
* @since 5.1
*/
XpathAssertions xpath(String expression, Map<String, String> namespaces, Object... args);
XpathAssertions xpath(String expression, @Nullable Map<String, String> namespaces, Object... args);
/**
* Assert the response body content with the given {@link Consumer}.

View File

@@ -21,18 +21,18 @@ import java.util.Map;
import java.util.Optional;
import javax.xml.xpath.XPathExpressionException;
import org.hamcrest.Matcher;
import org.w3c.dom.Node;
import org.springframework.http.HttpHeaders;
import org.springframework.lang.Nullable;
import org.springframework.test.util.XpathExpectationsHelper;
import org.springframework.util.Assert;
import org.springframework.util.MimeType;
/**
* XPath assertions for a {@link WebTestClient}.
* XPath assertions for the {@link WebTestClient}.
*
* @author Eric Deandrea
* @author Rossen Stoyanchev
* @since 5.1
*/
public class XpathAssertions {
@@ -41,96 +41,87 @@ public class XpathAssertions {
private final XpathExpectationsHelper xpathHelper;
XpathAssertions(WebTestClient.BodyContentSpec spec, String expression, @Nullable Map<String, String> namespaces, Object... args) throws XPathExpressionException {
XpathAssertions(WebTestClient.BodyContentSpec spec,
String expression, @Nullable Map<String, String> namespaces, Object... args) {
this.bodySpec = spec;
this.xpathHelper = new XpathExpectationsHelper(expression, namespaces, args);
this.xpathHelper = initXpathHelper(expression, namespaces, args);
}
private static XpathExpectationsHelper initXpathHelper(
String expression, @Nullable Map<String, String> namespaces, Object[] args) {
try {
return new XpathExpectationsHelper(expression, namespaces, args);
}
catch (XPathExpressionException ex) {
throw new AssertionError("XML parsing error", ex);
}
}
/**
* Applies {@link XpathExpectationsHelper#assertString(byte[], String, String)}
* Delegates to {@link XpathExpectationsHelper#assertString(byte[], String, String)}
*/
public WebTestClient.BodyContentSpec isEqualTo(String expectedValue) {
return performXmlAssertionAndHandleError(() -> this.xpathHelper.assertString(getResponseBody(), getDefinedEncoding(), expectedValue));
return assertWith(() -> this.xpathHelper.assertString(getContent(), getCharset(), expectedValue));
}
/**
* Applies {@link XpathExpectationsHelper#assertNumber(byte[], String, Double)}
* Delegates to {@link XpathExpectationsHelper#assertNumber(byte[], String, Double)}
*/
public WebTestClient.BodyContentSpec isEqualTo(Double expectedValue) {
return performXmlAssertionAndHandleError(() -> this.xpathHelper.assertNumber(getResponseBody(), getDefinedEncoding(), expectedValue));
return assertWith(() -> this.xpathHelper.assertNumber(getContent(), getCharset(), expectedValue));
}
/**
* Applies {@link XpathExpectationsHelper#assertBoolean(byte[], String, boolean)}
* Delegates to {@link XpathExpectationsHelper#assertBoolean(byte[], String, boolean)}
*/
public WebTestClient.BodyContentSpec isEqualTo(boolean expectedValue) {
return performXmlAssertionAndHandleError(() -> this.xpathHelper.assertBoolean(getResponseBody(), getDefinedEncoding(), expectedValue));
return assertWith(() -> this.xpathHelper.assertBoolean(getContent(), getCharset(), expectedValue));
}
/**
* Applies {@link XpathExpectationsHelper#exists(byte[], String)}
* Delegates to {@link XpathExpectationsHelper#exists(byte[], String)}
*/
public WebTestClient.BodyContentSpec exists() {
return performXmlAssertionAndHandleError(() -> this.xpathHelper.exists(getResponseBody(), getDefinedEncoding()));
return assertWith(() -> this.xpathHelper.exists(getContent(), getCharset()));
}
/**
* Applies {@link XpathExpectationsHelper#doesNotExist(byte[], String)}
* Delegates to {@link XpathExpectationsHelper#doesNotExist(byte[], String)}
*/
public WebTestClient.BodyContentSpec doesNotExist() {
return performXmlAssertionAndHandleError(() -> this.xpathHelper.doesNotExist(getResponseBody(), getDefinedEncoding()));
return assertWith(() -> this.xpathHelper.doesNotExist(getContent(), getCharset()));
}
/**
* Applies {@link XpathExpectationsHelper[#assertNodeCount(byte[], String, int)}
* Delegates to {@link XpathExpectationsHelper[#assertNodeCount(byte[], String, int)}
*/
public WebTestClient.BodyContentSpec nodeCount(int expectedCount) {
return performXmlAssertionAndHandleError(() -> this.xpathHelper.assertNodeCount(getResponseBody(), getDefinedEncoding(), expectedCount));
return assertWith(() -> this.xpathHelper.assertNodeCount(getContent(), getCharset(), expectedCount));
}
/**
* Applies {@link XpathExpectationsHelper#assertNodeCount(byte[], String, Matcher)}
*/
public WebTestClient.BodyContentSpec nodeCount(Matcher<Integer> matcher) {
return performXmlAssertionAndHandleError(() -> this.xpathHelper.assertNodeCount(getResponseBody(), getDefinedEncoding(), matcher));
}
/**
* Applies {@link XpathExpectationsHelper#assertNode(byte[], String, Matcher)}
*/
public WebTestClient.BodyContentSpec nodeMatches(Matcher<? super Node> matcher) {
return performXmlAssertionAndHandleError(() -> this.xpathHelper.assertNode(getResponseBody(), getDefinedEncoding(), matcher));
}
/**
* Applies {@link XpathExpectationsHelper#assertString(byte[], String, Matcher)}
*/
public WebTestClient.BodyContentSpec matchesString(Matcher<? super String> matcher) {
return performXmlAssertionAndHandleError(() -> this.xpathHelper.assertString(getResponseBody(), getDefinedEncoding(), matcher));
}
/**
* Applies {@link XpathExpectationsHelper#assertNumber(byte[], String, Matcher)}
*/
public WebTestClient.BodyContentSpec matchesNumber(Matcher<? super Double> matcher) {
return performXmlAssertionAndHandleError(() -> this.xpathHelper.assertNumber(getResponseBody(), getDefinedEncoding(), matcher));
}
private WebTestClient.BodyContentSpec performXmlAssertionAndHandleError(AssertionThrowingRunnable assertion) {
assertion.run();
private WebTestClient.BodyContentSpec assertWith(CheckedExceptionTask task) {
try {
task.run();
}
catch (Exception ex) {
throw new AssertionError("XML parsing error", ex);
}
return this.bodySpec;
}
private byte[] getResponseBody() {
return getResult().getResponseBody();
private byte[] getContent() {
byte[] body = this.bodySpec.returnResult().getResponseBody();
Assert.notNull(body, "Expected body content");
return body;
}
private EntityExchangeResult<byte[]> getResult() {
return this.bodySpec.returnResult();
}
private String getDefinedEncoding() {
return Optional.ofNullable(getResult())
private String getCharset() {
return Optional.of(this.bodySpec.returnResult())
.map(EntityExchangeResult::getResponseHeaders)
.map(HttpHeaders::getContentType)
.map(MimeType::getCharset)
@@ -138,22 +129,14 @@ public class XpathAssertions {
.name();
}
/**
* Lets us be able to use lambda expressions that could throw checked exceptions, since
* {@link XpathExpectationsHelper} throws {@link Exception} on its methods.
*/
@FunctionalInterface
private interface AssertionThrowingRunnable extends Runnable {
void runThrows() throws Exception;
private interface CheckedExceptionTask {
void run() throws Exception;
@Override
default void run() {
try {
runThrows();
}
catch (Exception ex) {
throw new AssertionError("XML parsing error", ex);
}
}
}
}