Move response body directly in AbstractMockHttpServletResponseAssert
This commit removes ResponseBodyAssert and rather offers first-class access support for the response body at the root level using bodyText(), bodyJson(), and body(). This avoids a double navigation to assert the response body. See gh-32712
This commit is contained in:
@@ -52,7 +52,10 @@ import org.springframework.util.function.ThrowingBiFunction;
|
||||
* assertions} on the value.
|
||||
*
|
||||
* <p>Also support comparing the JSON document against a target, using
|
||||
* {@linkplain JSONCompare JSON Assert}.
|
||||
* {@linkplain JSONCompare JSON Assert}. Resources that are loaded from
|
||||
* the classpath can be relative if a {@linkplain #withResourceLoadClass(Class)
|
||||
* class} is provided. By default, {@code UTF-8} is used to load resources
|
||||
* but this can be overridden using {@link #withCharset(Charset)}.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @author Phillip Webb
|
||||
@@ -71,28 +74,27 @@ public abstract class AbstractJsonContentAssert<SELF extends AbstractJsonContent
|
||||
@Nullable
|
||||
private final GenericHttpMessageConverter<Object> jsonMessageConverter;
|
||||
|
||||
private final JsonLoader jsonLoader;
|
||||
@Nullable
|
||||
private Class<?> resourceLoadClass;
|
||||
|
||||
@Nullable
|
||||
private Charset charset;
|
||||
|
||||
private JsonLoader jsonLoader;
|
||||
|
||||
/**
|
||||
* Create an assert for the given JSON document.
|
||||
* <p>Path can be converted to a value object using the given
|
||||
* {@linkplain GenericHttpMessageConverter json message converter}.
|
||||
* <p>Resources to match can be loaded relative to the given
|
||||
* {@code resourceLoadClass}. If not specified, resources must always be
|
||||
* absolute. A specific {@link Charset} can be provided if {@code UTF-8} is
|
||||
* not suitable.
|
||||
* @param json the JSON document to assert
|
||||
* @param jsonMessageConverter the converter to use
|
||||
* @param resourceLoadClass the class used to load resources
|
||||
* @param charset the charset of the JSON resources
|
||||
* @param selfType the implementation type of this assert
|
||||
*/
|
||||
protected AbstractJsonContentAssert(@Nullable String json,
|
||||
@Nullable GenericHttpMessageConverter<Object> jsonMessageConverter, @Nullable Class<?> resourceLoadClass,
|
||||
@Nullable Charset charset, Class<?> selfType) {
|
||||
@Nullable GenericHttpMessageConverter<Object> jsonMessageConverter, Class<?> selfType) {
|
||||
super(json, selfType);
|
||||
this.jsonMessageConverter = jsonMessageConverter;
|
||||
this.jsonLoader = new JsonLoader(resourceLoadClass, charset);
|
||||
this.jsonLoader = new JsonLoader(null, null);
|
||||
as("JSON content");
|
||||
}
|
||||
|
||||
@@ -376,6 +378,31 @@ public abstract class AbstractJsonContentAssert<SELF extends AbstractJsonContent
|
||||
return isNotEqualTo(expected, JSONCompareMode.STRICT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Override the class used to load resources. Resources can be loaded from
|
||||
* an absolute location or relative to tpe specified class. For instance,
|
||||
* specifying {@code com.example.MyClass} as the resource class allows you
|
||||
* to use "my-file.json" to load {@code /com/example/my-file.json}.
|
||||
* @param resourceLoadClass the class used to load resources or {@code null}
|
||||
* to only use absolute paths.
|
||||
*/
|
||||
public SELF withResourceLoadClass(@Nullable Class<?> resourceLoadClass) {
|
||||
this.resourceLoadClass = resourceLoadClass;
|
||||
this.jsonLoader = new JsonLoader(resourceLoadClass, this.charset);
|
||||
return this.myself;
|
||||
}
|
||||
|
||||
/**
|
||||
* Override the {@link Charset} to use to load resources. By default,
|
||||
* resources are loaded using {@code UTF-8}.
|
||||
* @param charset the charset to use, or {@code null} to use the default
|
||||
*/
|
||||
public SELF withCharset(@Nullable Charset charset) {
|
||||
this.charset = charset;
|
||||
this.jsonLoader = new JsonLoader(this.resourceLoadClass, charset);
|
||||
return this.myself;
|
||||
}
|
||||
|
||||
|
||||
private JSONCompareResult compare(@Nullable CharSequence expectedJson, JSONCompareMode compareMode) {
|
||||
return compare(this.actual, expectedJson, (actualJsonString, expectedJsonString) ->
|
||||
|
||||
@@ -55,7 +55,7 @@ public final class JsonContent implements AssertProvider<JsonContentAssert> {
|
||||
*/
|
||||
@Override
|
||||
public JsonContentAssert assertThat() {
|
||||
return new JsonContentAssert(this.json, null, this.resourceLoadClass, null);
|
||||
return new JsonContentAssert(this.json, null).withResourceLoadClass(this.resourceLoadClass);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -16,8 +16,6 @@
|
||||
|
||||
package org.springframework.test.json;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
import org.springframework.http.converter.GenericHttpMessageConverter;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
@@ -33,19 +31,11 @@ public class JsonContentAssert extends AbstractJsonContentAssert<JsonContentAsse
|
||||
* Create an assert for the given JSON document.
|
||||
* <p>Path can be converted to a value object using the given
|
||||
* {@linkplain GenericHttpMessageConverter json message converter}.
|
||||
* <p>Resources to match can be loaded relative to the given
|
||||
* {@code resourceLoadClass}. If not specified, resources must always be
|
||||
* absolute. A specific {@link Charset} can be provided if {@code UTF-8} is
|
||||
* not suitable.
|
||||
* @param json the JSON document to assert
|
||||
* @param jsonMessageConverter the converter to use
|
||||
* @param resourceLoadClass the class used to load resources
|
||||
* @param charset the charset of the JSON resources
|
||||
*/
|
||||
public JsonContentAssert(@Nullable String json, @Nullable GenericHttpMessageConverter<Object> jsonMessageConverter,
|
||||
@Nullable Class<?> resourceLoadClass, @Nullable Charset charset) {
|
||||
|
||||
super(json, jsonMessageConverter, resourceLoadClass, charset, JsonContentAssert.class);
|
||||
public JsonContentAssert(@Nullable String json, @Nullable GenericHttpMessageConverter<Object> jsonMessageConverter) {
|
||||
super(json, jsonMessageConverter, JsonContentAssert.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -18,9 +18,16 @@ package org.springframework.test.web.servlet.assertj;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
import org.assertj.core.api.AbstractByteArrayAssert;
|
||||
import org.assertj.core.api.AbstractStringAssert;
|
||||
import org.assertj.core.api.Assertions;
|
||||
import org.assertj.core.api.ByteArrayAssert;
|
||||
|
||||
import org.springframework.http.converter.GenericHttpMessageConverter;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
import org.springframework.test.json.AbstractJsonContentAssert;
|
||||
import org.springframework.test.json.JsonContentAssert;
|
||||
import org.springframework.test.web.UriAssert;
|
||||
|
||||
/**
|
||||
@@ -45,22 +52,62 @@ public abstract class AbstractMockHttpServletResponseAssert<SELF extends Abstrac
|
||||
this.jsonMessageConverter = jsonMessageConverter;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return a new {@linkplain ResponseBodyAssert assertion} object that uses
|
||||
* the response body as the object to test. The returned assertion object
|
||||
* provides access to the raw byte array, a String value decoded using the
|
||||
* response's character encoding, and dedicated JSON testing support.
|
||||
* Return a new {@linkplain AbstractStringAssert assertion} object that uses
|
||||
* the response body converted to text as the object to test.
|
||||
* <p>Examples: <pre><code class='java'>
|
||||
* // Check that the response body is equal to "Hello World":
|
||||
* assertThat(response).body().isEqualTo("Hello World");
|
||||
*
|
||||
* // Check that the response body is strictly equal to the content of "test.json":
|
||||
* assertThat(response).body().json().isStrictlyEqualToJson("test.json");
|
||||
* assertThat(response).bodyText().isEqualTo("Hello World");
|
||||
* </code></pre>
|
||||
*/
|
||||
public ResponseBodyAssert body() {
|
||||
return new ResponseBodyAssert(getResponse().getContentAsByteArray(),
|
||||
Charset.forName(getResponse().getCharacterEncoding()), this.jsonMessageConverter);
|
||||
public AbstractStringAssert<?> bodyText() {
|
||||
return Assertions.assertThat(readBody());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a new {@linkplain AbstractJsonContentAssert assertion} object that
|
||||
* uses the response body converted to text as the object to test. Compared
|
||||
* to {@link #bodyText()}, the assertion object provides dedicated JSON
|
||||
* support.
|
||||
* <p>Examples: <pre><code class='java'>
|
||||
* // Check that the response body is strictly equal to the content of
|
||||
* // "/com/acme/sample/person-created.json":
|
||||
* assertThat(response).bodyJson()
|
||||
* .isStrictlyEqualToJson("/com/acme/sample/person-created.json");
|
||||
*
|
||||
* // Check that the response is strictly equal to the content of the
|
||||
* // specified file located in the same package as the PersonController:
|
||||
* assertThat(response).bodyJson().withResourceLoadClass(PersonController.class)
|
||||
* .isStrictlyEqualToJson("person-created.json");
|
||||
* </code></pre>
|
||||
* The returned assert object also supports JSON path expressions.
|
||||
* <p>Examples: <pre><code class='java'>
|
||||
* // Check that the JSON document does not have an "error" element
|
||||
* assertThat(response).bodyJson().doesNotHavePath("$.error");
|
||||
*
|
||||
* // Check that the JSON document as a top level "message" element
|
||||
* assertThat(response).bodyJson()
|
||||
* .extractingPath("$.message").asString().isEqualTo("hello");
|
||||
* </code></pre>
|
||||
*/
|
||||
public AbstractJsonContentAssert<?> bodyJson() {
|
||||
return new JsonContentAssert(readBody(), this.jsonMessageConverter);
|
||||
}
|
||||
|
||||
private String readBody() {
|
||||
return new String(getResponse().getContentAsByteArray(),
|
||||
Charset.forName(getResponse().getCharacterEncoding()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a new {@linkplain AbstractByteArrayAssert assertion} object that
|
||||
* uses the response body as the object to test.
|
||||
* @see #bodyText()
|
||||
* @see #bodyJson()
|
||||
*/
|
||||
public AbstractByteArrayAssert<?> body() {
|
||||
return new ByteArrayAssert(getResponse().getContentAsByteArray());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -89,6 +136,14 @@ public abstract class AbstractMockHttpServletResponseAssert<SELF extends Abstrac
|
||||
return new UriAssert(getResponse().getRedirectedUrl(), "Redirected URL");
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that the response body is equal to the given value.
|
||||
*/
|
||||
public SELF hasBodyTextEqualTo(String bodyText) {
|
||||
bodyText().isEqualTo(bodyText);
|
||||
return this.myself;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that the forwarded URL is equal to the given value.
|
||||
* @param forwardedUrl the expected forwarded URL (can be null)
|
||||
|
||||
@@ -1,130 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2024 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
|
||||
*
|
||||
* https://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.servlet.assertj;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.assertj.core.api.AbstractByteArrayAssert;
|
||||
import org.assertj.core.api.AbstractStringAssert;
|
||||
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.http.converter.GenericHttpMessageConverter;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.test.json.AbstractJsonContentAssert;
|
||||
import org.springframework.test.json.JsonContentAssert;
|
||||
|
||||
/**
|
||||
* AssertJ {@link org.assertj.core.api.Assert assertions} that can be applied to
|
||||
* the response body.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @author Brian Clozel
|
||||
* @since 6.2
|
||||
*/
|
||||
public class ResponseBodyAssert extends AbstractByteArrayAssert<ResponseBodyAssert> {
|
||||
|
||||
private final Charset characterEncoding;
|
||||
|
||||
@Nullable
|
||||
private final GenericHttpMessageConverter<Object> jsonMessageConverter;
|
||||
|
||||
ResponseBodyAssert(byte[] actual, Charset characterEncoding,
|
||||
@Nullable GenericHttpMessageConverter<Object> jsonMessageConverter) {
|
||||
|
||||
super(actual, ResponseBodyAssert.class);
|
||||
this.characterEncoding = characterEncoding;
|
||||
this.jsonMessageConverter = jsonMessageConverter;
|
||||
as("Response body");
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a new {@linkplain AbstractJsonContentAssert assertion} object that
|
||||
* provides {@linkplain com.jayway.jsonpath.JsonPath JSON path} assertions on
|
||||
* the response body.
|
||||
*/
|
||||
public AbstractJsonContentAssert<?> jsonPath() {
|
||||
return new JsonContentAssert(getJson(), this.jsonMessageConverter, null, this.characterEncoding)
|
||||
.as("JSON body");
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a new {@linkplain AbstractJsonContentAssert assertion} object that
|
||||
* provides support for {@linkplain org.skyscreamer.jsonassert.JSONCompareMode
|
||||
* JSON assert} comparisons against expected JSON input which can be loaded
|
||||
* from the classpath.
|
||||
* <p>This method only supports absolute locations for JSON documents loaded
|
||||
* from the classpath. Consider using {@link #json(Class)} to load JSON
|
||||
* documents relative to a given class.
|
||||
* <p>Example: <pre><code class='java'>
|
||||
* // Check that the response is strictly equal to the content of
|
||||
* // "/com/acme/web/person/person-created.json":
|
||||
* assertThat(...).body().json()
|
||||
* .isStrictlyEqualToJson("/com/acme/web/person/person-created.json");
|
||||
* </code></pre>
|
||||
*/
|
||||
public AbstractJsonContentAssert<?> json() {
|
||||
return json(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a new {@linkplain AbstractJsonContentAssert assertion} object that
|
||||
* provides support for {@linkplain org.skyscreamer.jsonassert.JSONCompareMode
|
||||
* JSON assert} comparisons against expected JSON input which can be loaded
|
||||
* from the classpath.
|
||||
* <p>Locations for JSON documents can be absolute using a leading slash, or
|
||||
* relative to the given {@code resourceLoadClass}.
|
||||
* <p>Example: <pre><code class='java'>
|
||||
* // Check that the response is strictly equal to the content of the
|
||||
* // specified file located in the same package as the PersonController:
|
||||
* assertThat(...).body().json(PersonController.class)
|
||||
* .isStrictlyEqualToJson("person-created.json");
|
||||
* </code></pre>
|
||||
* @param resourceLoadClass the class used to load relative JSON documents
|
||||
* @see ClassPathResource#ClassPathResource(String, Class)
|
||||
*/
|
||||
public AbstractJsonContentAssert<?> json(@Nullable Class<?> resourceLoadClass) {
|
||||
return new JsonContentAssert(getJson(), this.jsonMessageConverter, resourceLoadClass, this.characterEncoding)
|
||||
.as("JSON body");
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that the response body is equal to the given {@link String}.
|
||||
* <p>Converts the actual byte array to a String using the character encoding
|
||||
* of the {@link HttpServletResponse}.
|
||||
* @param expected the expected content of the response body
|
||||
* @see #asString()
|
||||
*/
|
||||
public ResponseBodyAssert isEqualTo(String expected) {
|
||||
asString().isEqualTo(expected);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Override that uses the character encoding of the {@link HttpServletResponse}
|
||||
* to convert the byte[] to a String, rather than the platform's default charset.
|
||||
*/
|
||||
@Override
|
||||
public AbstractStringAssert<?> asString() {
|
||||
return asString(this.characterEncoding);
|
||||
}
|
||||
|
||||
private String getJson() {
|
||||
return new String(this.actual, this.characterEncoding);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -19,7 +19,6 @@ package org.springframework.test.json;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
@@ -146,7 +145,6 @@ class AbstractJsonContentAssertTests {
|
||||
assertThat(forJson(NULLS)).doesNotHavePath("$.missing");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void doesNotHavePathForPresent() {
|
||||
String expression = "$.valuename";
|
||||
@@ -154,7 +152,6 @@ class AbstractJsonContentAssertTests {
|
||||
.isThrownBy(() -> assertThat(forJson(NULLS)).doesNotHavePath(expression))
|
||||
.satisfies(hasFailedToNotMatchPath(expression));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Nested
|
||||
@@ -330,13 +327,12 @@ class AbstractJsonContentAssertTests {
|
||||
private record Customer(long id, String username) {}
|
||||
|
||||
private AssertProvider<AbstractJsonContentAssert<?>> forJson(@Nullable String json) {
|
||||
return () -> new TestJsonContentAssert(json, null, null, null);
|
||||
return () -> new TestJsonContentAssert(json, null);
|
||||
}
|
||||
|
||||
private AssertProvider<AbstractJsonContentAssert<?>> forJson(@Nullable String json, GenericHttpMessageConverter<Object> jsonHttpMessageConverter) {
|
||||
return () -> new TestJsonContentAssert(json, jsonHttpMessageConverter, null, null);
|
||||
return () -> new TestJsonContentAssert(json, jsonHttpMessageConverter);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Nested
|
||||
@@ -548,7 +544,6 @@ class AbstractJsonContentAssertTests {
|
||||
.isThrownBy(() -> assertThat(forJson(SOURCE)).isStrictlyEqualTo(expected));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void isNotEqualToWhenStringIsMatchingShouldFail() {
|
||||
assertThatExceptionOfType(AssertionError.class)
|
||||
@@ -720,10 +715,19 @@ class AbstractJsonContentAssertTests {
|
||||
assertThat(forJson(SOURCE)).isNotStrictlyEqualTo(expected);
|
||||
}
|
||||
|
||||
private AssertProvider<AbstractJsonContentAssert<?>> forJson(@Nullable String json) {
|
||||
return () -> new TestJsonContentAssert(json, null, getClass(), null);
|
||||
@Test
|
||||
void withResourceLoadClassShouldAllowToLoadRelativeContent() {
|
||||
AbstractJsonContentAssert<?> jsonAssert = assertThat(forJson(NULLS)).withResourceLoadClass(String.class);
|
||||
assertThatIllegalStateException()
|
||||
.isThrownBy(() -> jsonAssert.isLenientlyEqualTo("nulls.json"))
|
||||
.withMessage("Unable to load JSON from class path resource [java/lang/nulls.json]");
|
||||
|
||||
assertThat(forJson(NULLS)).withResourceLoadClass(JsonContent.class).isLenientlyEqualTo("nulls.json");
|
||||
}
|
||||
|
||||
private AssertProvider<AbstractJsonContentAssert<?>> forJson(@Nullable String json) {
|
||||
return () -> new TestJsonContentAssert(json, null).withResourceLoadClass(getClass());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -768,13 +772,13 @@ class AbstractJsonContentAssertTests {
|
||||
}
|
||||
|
||||
private AssertProvider<AbstractJsonContentAssert<?>> forJson(@Nullable String json) {
|
||||
return () -> new TestJsonContentAssert(json, null, null, null);
|
||||
return () -> new TestJsonContentAssert(json, null);
|
||||
}
|
||||
|
||||
private static class TestJsonContentAssert extends AbstractJsonContentAssert<TestJsonContentAssert> {
|
||||
|
||||
public TestJsonContentAssert(@Nullable String json, @Nullable GenericHttpMessageConverter<Object> jsonMessageConverter, @Nullable Class<?> resourceLoadClass, @Nullable Charset charset) {
|
||||
super(json, jsonMessageConverter, resourceLoadClass, charset, TestJsonContentAssert.class);
|
||||
public TestJsonContentAssert(@Nullable String json, @Nullable GenericHttpMessageConverter<Object> jsonMessageConverter) {
|
||||
super(json, jsonMessageConverter, TestJsonContentAssert.class);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -16,15 +16,17 @@
|
||||
|
||||
package org.springframework.test.web.servlet.assertj;
|
||||
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import org.assertj.core.api.AssertProvider;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
import org.springframework.test.json.JsonContent;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
|
||||
/**
|
||||
@@ -34,12 +36,50 @@ import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
*/
|
||||
public class AbstractMockHttpServletResponseAssertTests {
|
||||
|
||||
@Test
|
||||
void bodyText() {
|
||||
MockHttpServletResponse response = createResponse("OK");
|
||||
assertThat(fromResponse(response)).bodyText().isEqualTo("OK");
|
||||
}
|
||||
|
||||
@Test
|
||||
void bodyJsonWithJsonPath() {
|
||||
MockHttpServletResponse response = createResponse("{\"albumById\": {\"name\": \"Greatest hits\"}}");
|
||||
assertThat(fromResponse(response)).bodyJson()
|
||||
.extractingPath("$.albumById.name").isEqualTo("Greatest hits");
|
||||
}
|
||||
|
||||
@Test
|
||||
void bodyJsonCanLoadResourceRelativeToClass() {
|
||||
MockHttpServletResponse response = createResponse("{ \"name\" : \"Spring\", \"age\" : 123 }");
|
||||
// See org/springframework/test/json/example.json
|
||||
assertThat(fromResponse(response)).bodyJson().withResourceLoadClass(JsonContent.class)
|
||||
.isLenientlyEqualTo("example.json");
|
||||
}
|
||||
|
||||
@Test
|
||||
void bodyWithByteArray() throws UnsupportedEncodingException {
|
||||
byte[] bytes = "OK".getBytes(StandardCharsets.UTF_8);
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
response.getWriter().write("OK");
|
||||
response.setContentType(StandardCharsets.UTF_8.name());
|
||||
assertThat(fromResponse(response)).body().isEqualTo(bytes);
|
||||
}
|
||||
|
||||
@Test
|
||||
void hasBodyTextEqualTo() throws UnsupportedEncodingException {
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
response.getWriter().write("OK");
|
||||
response.setContentType(StandardCharsets.UTF_8.name());
|
||||
assertThat(fromResponse(response)).hasBodyTextEqualTo("OK");
|
||||
}
|
||||
|
||||
@Test
|
||||
void hasForwardedUrl() {
|
||||
String forwardedUrl = "https://example.com/42";
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
response.setForwardedUrl(forwardedUrl);
|
||||
assertThat(response).hasForwardedUrl(forwardedUrl);
|
||||
assertThat(fromResponse(response)).hasForwardedUrl(forwardedUrl);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -48,7 +88,7 @@ public class AbstractMockHttpServletResponseAssertTests {
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
response.setForwardedUrl(forwardedUrl);
|
||||
assertThatExceptionOfType(AssertionError.class)
|
||||
.isThrownBy(() -> assertThat(response).hasForwardedUrl("another"))
|
||||
.isThrownBy(() -> assertThat(fromResponse(response)).hasForwardedUrl("another"))
|
||||
.withMessageContainingAll("Forwarded URL", forwardedUrl, "another");
|
||||
}
|
||||
|
||||
@@ -57,7 +97,7 @@ public class AbstractMockHttpServletResponseAssertTests {
|
||||
String redirectedUrl = "https://example.com/42";
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
response.addHeader(HttpHeaders.LOCATION, redirectedUrl);
|
||||
assertThat(response).hasRedirectedUrl(redirectedUrl);
|
||||
assertThat(fromResponse(response)).hasRedirectedUrl(redirectedUrl);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -66,29 +106,25 @@ public class AbstractMockHttpServletResponseAssertTests {
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
response.addHeader(HttpHeaders.LOCATION, redirectedUrl);
|
||||
assertThatExceptionOfType(AssertionError.class)
|
||||
.isThrownBy(() -> assertThat(response).hasRedirectedUrl("another"))
|
||||
.isThrownBy(() -> assertThat(fromResponse(response)).hasRedirectedUrl("another"))
|
||||
.withMessageContainingAll("Redirected URL", redirectedUrl, "another");
|
||||
}
|
||||
|
||||
@Test
|
||||
void bodyHasContent() throws UnsupportedEncodingException {
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
response.getWriter().write("OK");
|
||||
assertThat(response).body().asString().isEqualTo("OK");
|
||||
|
||||
private MockHttpServletResponse createResponse(String body) {
|
||||
try {
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
response.setContentType(StandardCharsets.UTF_8.name());
|
||||
response.getWriter().write(body);
|
||||
return response;
|
||||
}
|
||||
catch (UnsupportedEncodingException ex) {
|
||||
throw new IllegalStateException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void bodyHasContentWithResponseCharacterEncoding() throws UnsupportedEncodingException {
|
||||
byte[] bytes = "OK".getBytes(StandardCharsets.UTF_8);
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
response.getWriter().write("OK");
|
||||
response.setContentType(StandardCharsets.UTF_8.name());
|
||||
assertThat(response).body().isEqualTo(bytes);
|
||||
}
|
||||
|
||||
|
||||
private static ResponseAssert assertThat(MockHttpServletResponse response) {
|
||||
return new ResponseAssert(response);
|
||||
private static AssertProvider<ResponseAssert> fromResponse(MockHttpServletResponse response) {
|
||||
return () -> new ResponseAssert(response);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -250,19 +250,19 @@ public class AssertableMockMvcIntegrationTests {
|
||||
|
||||
@Test
|
||||
void jsonPathContent() {
|
||||
assertThat(perform(get("/message"))).body().jsonPath()
|
||||
assertThat(perform(get("/message"))).bodyJson()
|
||||
.extractingPath("$.message").asString().isEqualTo("hello");
|
||||
}
|
||||
|
||||
@Test
|
||||
void jsonContentCanLoadResourceFromClasspath() {
|
||||
assertThat(perform(get("/message"))).body().json().isLenientlyEqualTo(
|
||||
assertThat(perform(get("/message"))).bodyJson().isLenientlyEqualTo(
|
||||
new ClassPathResource("message.json", AssertableMockMvcIntegrationTests.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void jsonContentUsingResourceLoaderClass() {
|
||||
assertThat(perform(get("/message"))).body().json(AssertableMockMvcIntegrationTests.class)
|
||||
assertThat(perform(get("/message"))).bodyJson().withResourceLoadClass(AssertableMockMvcIntegrationTests.class)
|
||||
.isLenientlyEqualTo("message.json");
|
||||
}
|
||||
|
||||
|
||||
@@ -67,26 +67,26 @@ class AssertableMockMvcTests {
|
||||
void createWithExistingWebApplicationContext() {
|
||||
try (GenericWebApplicationContext wac = create(WebConfiguration.class)) {
|
||||
AssertableMockMvc mockMvc = AssertableMockMvc.from(wac);
|
||||
assertThat(mockMvc.perform(post("/increase"))).body().isEqualTo("counter 41");
|
||||
assertThat(mockMvc.perform(post("/increase"))).body().isEqualTo("counter 42");
|
||||
assertThat(mockMvc.perform(post("/increase"))).hasBodyTextEqualTo("counter 41");
|
||||
assertThat(mockMvc.perform(post("/increase"))).hasBodyTextEqualTo("counter 42");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void createWithControllerClassShouldInstantiateControllers() {
|
||||
AssertableMockMvc mockMvc = AssertableMockMvc.of(HelloController.class, CounterController.class);
|
||||
assertThat(mockMvc.perform(get("/hello"))).body().isEqualTo("Hello World");
|
||||
assertThat(mockMvc.perform(post("/increase"))).body().isEqualTo("counter 1");
|
||||
assertThat(mockMvc.perform(post("/increase"))).body().isEqualTo("counter 2");
|
||||
assertThat(mockMvc.perform(get("/hello"))).hasBodyTextEqualTo("Hello World");
|
||||
assertThat(mockMvc.perform(post("/increase"))).hasBodyTextEqualTo("counter 1");
|
||||
assertThat(mockMvc.perform(post("/increase"))).hasBodyTextEqualTo("counter 2");
|
||||
}
|
||||
|
||||
@Test
|
||||
void createWithControllersShouldUseThemAsIs() {
|
||||
AssertableMockMvc mockMvc = AssertableMockMvc.of(new HelloController(),
|
||||
new CounterController(new AtomicInteger(41)));
|
||||
assertThat(mockMvc.perform(get("/hello"))).body().isEqualTo("Hello World");
|
||||
assertThat(mockMvc.perform(post("/increase"))).body().isEqualTo("counter 42");
|
||||
assertThat(mockMvc.perform(post("/increase"))).body().isEqualTo("counter 43");
|
||||
assertThat(mockMvc.perform(get("/hello"))).hasBodyTextEqualTo("Hello World");
|
||||
assertThat(mockMvc.perform(post("/increase"))).hasBodyTextEqualTo("counter 42");
|
||||
assertThat(mockMvc.perform(post("/increase"))).hasBodyTextEqualTo("counter 43");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -99,7 +99,7 @@ class AssertableMockMvcTests {
|
||||
@Test
|
||||
void createWithControllersHasNoHttpMessageConverter() {
|
||||
AssertableMockMvc mockMvc = AssertableMockMvc.of(new HelloController());
|
||||
AbstractJsonContentAssert<?> jsonContentAssert = assertThat(mockMvc.perform(get("/json"))).hasStatusOk().body().jsonPath();
|
||||
AbstractJsonContentAssert<?> jsonContentAssert = assertThat(mockMvc.perform(get("/json"))).hasStatusOk().bodyJson();
|
||||
assertThatIllegalStateException()
|
||||
.isThrownBy(() -> jsonContentAssert.extractingPath("$").convertTo(Message.class))
|
||||
.withMessageContaining("No JSON message converter available");
|
||||
@@ -109,7 +109,7 @@ class AssertableMockMvcTests {
|
||||
void createWithControllerCanConfigureHttpMessageConverters() {
|
||||
AssertableMockMvc mockMvc = AssertableMockMvc.of(HelloController.class)
|
||||
.withHttpMessageConverters(List.of(jsonHttpMessageConverter));
|
||||
assertThat(mockMvc.perform(get("/json"))).hasStatusOk().body().jsonPath()
|
||||
assertThat(mockMvc.perform(get("/json"))).hasStatusOk().bodyJson()
|
||||
.extractingPath("$").convertTo(Message.class).satisfies(message -> {
|
||||
assertThat(message.message()).isEqualTo("Hello World");
|
||||
assertThat(message.counter()).isEqualTo(42);
|
||||
@@ -122,7 +122,7 @@ class AssertableMockMvcTests {
|
||||
MappingJackson2HttpMessageConverter converter = spy(jsonHttpMessageConverter);
|
||||
AssertableMockMvc mockMvc = AssertableMockMvc.of(HelloController.class)
|
||||
.withHttpMessageConverters(List.of(mock(), mock(), converter));
|
||||
assertThat(mockMvc.perform(get("/json"))).hasStatusOk().body().jsonPath()
|
||||
assertThat(mockMvc.perform(get("/json"))).hasStatusOk().bodyJson()
|
||||
.extractingPath("$").convertTo(Message.class).satisfies(message -> {
|
||||
assertThat(message.message()).isEqualTo("Hello World");
|
||||
assertThat(message.counter()).isEqualTo(42);
|
||||
|
||||
@@ -1,88 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2024 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
|
||||
*
|
||||
* https://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.servlet.assertj;
|
||||
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import org.assertj.core.api.AssertProvider;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
import org.springframework.test.json.JsonContent;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link ResponseBodyAssert}.
|
||||
*
|
||||
* @author Brian Clozel
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
class ResponseBodyAssertTests {
|
||||
|
||||
@Test
|
||||
void isEqualToWithByteArray() {
|
||||
MockHttpServletResponse response = createResponse("hello");
|
||||
response.setCharacterEncoding(StandardCharsets.UTF_8.name());
|
||||
assertThat(fromResponse(response)).isEqualTo("hello".getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
|
||||
@Test
|
||||
void isEqualToWithString() {
|
||||
MockHttpServletResponse response = createResponse("hello");
|
||||
assertThat(fromResponse(response)).isEqualTo("hello");
|
||||
}
|
||||
|
||||
@Test
|
||||
void jsonPathWithJsonResponseShouldPass() {
|
||||
MockHttpServletResponse response = createResponse("{\"message\": \"hello\"}");
|
||||
assertThat(fromResponse(response)).jsonPath().extractingPath("$.message").isEqualTo("hello");
|
||||
}
|
||||
|
||||
@Test
|
||||
void jsonPathWithJsonCompatibleResponseShouldPass() {
|
||||
MockHttpServletResponse response = createResponse("{\"albumById\": {\"name\": \"Greatest hits\"}}");
|
||||
assertThat(fromResponse(response)).jsonPath()
|
||||
.extractingPath("$.albumById.name").isEqualTo("Greatest hits");
|
||||
}
|
||||
|
||||
@Test
|
||||
void jsonCanLoadResourceRelativeToClass() {
|
||||
MockHttpServletResponse response = createResponse("{ \"name\" : \"Spring\", \"age\" : 123 }");
|
||||
// See org/springframework/test/json/example.json
|
||||
assertThat(fromResponse(response)).json(JsonContent.class).isLenientlyEqualTo("example.json");
|
||||
}
|
||||
|
||||
private MockHttpServletResponse createResponse(String body) {
|
||||
try {
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
response.getWriter().print(body);
|
||||
return response;
|
||||
}
|
||||
catch (UnsupportedEncodingException ex) {
|
||||
throw new IllegalStateException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
private AssertProvider<ResponseBodyAssert> fromResponse(MockHttpServletResponse response) {
|
||||
return () -> new ResponseBodyAssert(response.getContentAsByteArray(), Charset.forName(response.getCharacterEncoding()), null);
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user