Skip to content

Commit 5567d14

Browse files
committed
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
1 parent 24cc776 commit 5567d14

10 files changed

+193
-299
lines changed

Diff for: spring-test/src/main/java/org/springframework/test/json/AbstractJsonContentAssert.java

+38-11
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,10 @@
5252
* assertions} on the value.
5353
*
5454
* <p>Also support comparing the JSON document against a target, using
55-
* {@linkplain JSONCompare JSON Assert}.
55+
* {@linkplain JSONCompare JSON Assert}. Resources that are loaded from
56+
* the classpath can be relative if a {@linkplain #withResourceLoadClass(Class)
57+
* class} is provided. By default, {@code UTF-8} is used to load resources
58+
* but this can be overridden using {@link #withCharset(Charset)}.
5659
*
5760
* @author Stephane Nicoll
5861
* @author Phillip Webb
@@ -71,28 +74,27 @@ public abstract class AbstractJsonContentAssert<SELF extends AbstractJsonContent
7174
@Nullable
7275
private final GenericHttpMessageConverter<Object> jsonMessageConverter;
7376

74-
private final JsonLoader jsonLoader;
77+
@Nullable
78+
private Class<?> resourceLoadClass;
79+
80+
@Nullable
81+
private Charset charset;
82+
83+
private JsonLoader jsonLoader;
7584

7685
/**
7786
* Create an assert for the given JSON document.
7887
* <p>Path can be converted to a value object using the given
7988
* {@linkplain GenericHttpMessageConverter json message converter}.
80-
* <p>Resources to match can be loaded relative to the given
81-
* {@code resourceLoadClass}. If not specified, resources must always be
82-
* absolute. A specific {@link Charset} can be provided if {@code UTF-8} is
83-
* not suitable.
8489
* @param json the JSON document to assert
8590
* @param jsonMessageConverter the converter to use
86-
* @param resourceLoadClass the class used to load resources
87-
* @param charset the charset of the JSON resources
8891
* @param selfType the implementation type of this assert
8992
*/
9093
protected AbstractJsonContentAssert(@Nullable String json,
91-
@Nullable GenericHttpMessageConverter<Object> jsonMessageConverter, @Nullable Class<?> resourceLoadClass,
92-
@Nullable Charset charset, Class<?> selfType) {
94+
@Nullable GenericHttpMessageConverter<Object> jsonMessageConverter, Class<?> selfType) {
9395
super(json, selfType);
9496
this.jsonMessageConverter = jsonMessageConverter;
95-
this.jsonLoader = new JsonLoader(resourceLoadClass, charset);
97+
this.jsonLoader = new JsonLoader(null, null);
9698
as("JSON content");
9799
}
98100

@@ -376,6 +378,31 @@ public SELF isNotStrictlyEqualTo(Resource expected) {
376378
return isNotEqualTo(expected, JSONCompareMode.STRICT);
377379
}
378380

381+
/**
382+
* Override the class used to load resources. Resources can be loaded from
383+
* an absolute location or relative to tpe specified class. For instance,
384+
* specifying {@code com.example.MyClass} as the resource class allows you
385+
* to use "my-file.json" to load {@code /com/example/my-file.json}.
386+
* @param resourceLoadClass the class used to load resources or {@code null}
387+
* to only use absolute paths.
388+
*/
389+
public SELF withResourceLoadClass(@Nullable Class<?> resourceLoadClass) {
390+
this.resourceLoadClass = resourceLoadClass;
391+
this.jsonLoader = new JsonLoader(resourceLoadClass, this.charset);
392+
return this.myself;
393+
}
394+
395+
/**
396+
* Override the {@link Charset} to use to load resources. By default,
397+
* resources are loaded using {@code UTF-8}.
398+
* @param charset the charset to use, or {@code null} to use the default
399+
*/
400+
public SELF withCharset(@Nullable Charset charset) {
401+
this.charset = charset;
402+
this.jsonLoader = new JsonLoader(this.resourceLoadClass, charset);
403+
return this.myself;
404+
}
405+
379406

380407
private JSONCompareResult compare(@Nullable CharSequence expectedJson, JSONCompareMode compareMode) {
381408
return compare(this.actual, expectedJson, (actualJsonString, expectedJsonString) ->

Diff for: spring-test/src/main/java/org/springframework/test/json/JsonContent.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ public final class JsonContent implements AssertProvider<JsonContentAssert> {
5555
*/
5656
@Override
5757
public JsonContentAssert assertThat() {
58-
return new JsonContentAssert(this.json, null, this.resourceLoadClass, null);
58+
return new JsonContentAssert(this.json, null).withResourceLoadClass(this.resourceLoadClass);
5959
}
6060

6161
/**

Diff for: spring-test/src/main/java/org/springframework/test/json/JsonContentAssert.java

+2-12
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,6 @@
1616

1717
package org.springframework.test.json;
1818

19-
import java.nio.charset.Charset;
20-
2119
import org.springframework.http.converter.GenericHttpMessageConverter;
2220
import org.springframework.lang.Nullable;
2321

@@ -33,19 +31,11 @@ public class JsonContentAssert extends AbstractJsonContentAssert<JsonContentAsse
3331
* Create an assert for the given JSON document.
3432
* <p>Path can be converted to a value object using the given
3533
* {@linkplain GenericHttpMessageConverter json message converter}.
36-
* <p>Resources to match can be loaded relative to the given
37-
* {@code resourceLoadClass}. If not specified, resources must always be
38-
* absolute. A specific {@link Charset} can be provided if {@code UTF-8} is
39-
* not suitable.
4034
* @param json the JSON document to assert
4135
* @param jsonMessageConverter the converter to use
42-
* @param resourceLoadClass the class used to load resources
43-
* @param charset the charset of the JSON resources
4436
*/
45-
public JsonContentAssert(@Nullable String json, @Nullable GenericHttpMessageConverter<Object> jsonMessageConverter,
46-
@Nullable Class<?> resourceLoadClass, @Nullable Charset charset) {
47-
48-
super(json, jsonMessageConverter, resourceLoadClass, charset, JsonContentAssert.class);
37+
public JsonContentAssert(@Nullable String json, @Nullable GenericHttpMessageConverter<Object> jsonMessageConverter) {
38+
super(json, jsonMessageConverter, JsonContentAssert.class);
4939
}
5040

5141
}

Diff for: spring-test/src/main/java/org/springframework/test/web/servlet/assertj/AbstractMockHttpServletResponseAssert.java

+65-10
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,16 @@
1818

1919
import java.nio.charset.Charset;
2020

21+
import org.assertj.core.api.AbstractByteArrayAssert;
22+
import org.assertj.core.api.AbstractStringAssert;
23+
import org.assertj.core.api.Assertions;
24+
import org.assertj.core.api.ByteArrayAssert;
25+
2126
import org.springframework.http.converter.GenericHttpMessageConverter;
2227
import org.springframework.lang.Nullable;
2328
import org.springframework.mock.web.MockHttpServletResponse;
29+
import org.springframework.test.json.AbstractJsonContentAssert;
30+
import org.springframework.test.json.JsonContentAssert;
2431
import org.springframework.test.web.UriAssert;
2532

2633
/**
@@ -45,22 +52,62 @@ protected AbstractMockHttpServletResponseAssert(
4552
this.jsonMessageConverter = jsonMessageConverter;
4653
}
4754

55+
4856
/**
49-
* Return a new {@linkplain ResponseBodyAssert assertion} object that uses
50-
* the response body as the object to test. The returned assertion object
51-
* provides access to the raw byte array, a String value decoded using the
52-
* response's character encoding, and dedicated JSON testing support.
57+
* Return a new {@linkplain AbstractStringAssert assertion} object that uses
58+
* the response body converted to text as the object to test.
5359
* <p>Examples: <pre><code class='java'>
5460
* // Check that the response body is equal to "Hello World":
55-
* assertThat(response).body().isEqualTo("Hello World");
61+
* assertThat(response).bodyText().isEqualTo("Hello World");
62+
* </code></pre>
63+
*/
64+
public AbstractStringAssert<?> bodyText() {
65+
return Assertions.assertThat(readBody());
66+
}
67+
68+
/**
69+
* Return a new {@linkplain AbstractJsonContentAssert assertion} object that
70+
* uses the response body converted to text as the object to test. Compared
71+
* to {@link #bodyText()}, the assertion object provides dedicated JSON
72+
* support.
73+
* <p>Examples: <pre><code class='java'>
74+
* // Check that the response body is strictly equal to the content of
75+
* // "/com/acme/sample/person-created.json":
76+
* assertThat(response).bodyJson()
77+
* .isStrictlyEqualToJson("/com/acme/sample/person-created.json");
78+
*
79+
* // Check that the response is strictly equal to the content of the
80+
* // specified file located in the same package as the PersonController:
81+
* assertThat(response).bodyJson().withResourceLoadClass(PersonController.class)
82+
* .isStrictlyEqualToJson("person-created.json");
83+
* </code></pre>
84+
* The returned assert object also supports JSON path expressions.
85+
* <p>Examples: <pre><code class='java'>
86+
* // Check that the JSON document does not have an "error" element
87+
* assertThat(response).bodyJson().doesNotHavePath("$.error");
5688
*
57-
* // Check that the response body is strictly equal to the content of "test.json":
58-
* assertThat(response).body().json().isStrictlyEqualToJson("test.json");
89+
* // Check that the JSON document as a top level "message" element
90+
* assertThat(response).bodyJson()
91+
* .extractingPath("$.message").asString().isEqualTo("hello");
5992
* </code></pre>
6093
*/
61-
public ResponseBodyAssert body() {
62-
return new ResponseBodyAssert(getResponse().getContentAsByteArray(),
63-
Charset.forName(getResponse().getCharacterEncoding()), this.jsonMessageConverter);
94+
public AbstractJsonContentAssert<?> bodyJson() {
95+
return new JsonContentAssert(readBody(), this.jsonMessageConverter);
96+
}
97+
98+
private String readBody() {
99+
return new String(getResponse().getContentAsByteArray(),
100+
Charset.forName(getResponse().getCharacterEncoding()));
101+
}
102+
103+
/**
104+
* Return a new {@linkplain AbstractByteArrayAssert assertion} object that
105+
* uses the response body as the object to test.
106+
* @see #bodyText()
107+
* @see #bodyJson()
108+
*/
109+
public AbstractByteArrayAssert<?> body() {
110+
return new ByteArrayAssert(getResponse().getContentAsByteArray());
64111
}
65112

66113
/**
@@ -89,6 +136,14 @@ public UriAssert redirectedUrl() {
89136
return new UriAssert(getResponse().getRedirectedUrl(), "Redirected URL");
90137
}
91138

139+
/**
140+
* Verify that the response body is equal to the given value.
141+
*/
142+
public SELF hasBodyTextEqualTo(String bodyText) {
143+
bodyText().isEqualTo(bodyText);
144+
return this.myself;
145+
}
146+
92147
/**
93148
* Verify that the forwarded URL is equal to the given value.
94149
* @param forwardedUrl the expected forwarded URL (can be null)

Diff for: spring-test/src/main/java/org/springframework/test/web/servlet/assertj/ResponseBodyAssert.java

-130
This file was deleted.

0 commit comments

Comments
 (0)