Browse Source

Add support for strict JSON comparison in WebTestClient

Prior to this commit, WebTestClient only supported "lenient" comparison
of the expected JSON body.

This commit introduces an overloaded variant of `json()` in the
BodyContentSpec that accepts an additional boolean flag to specify
whether a "strict" comparison should be performed.

This new feature is analogous to the existing support in MockMvc.

Closes gh-27993
pull/28119/head
Gleidson Leopoldo 3 years ago committed by Sam Brannen
parent
commit
920be8e1b2
  1. 4
      spring-test/src/main/java/org/springframework/test/web/reactive/server/DefaultWebTestClient.java
  2. 19
      spring-test/src/main/java/org/springframework/test/web/reactive/server/WebTestClient.java
  3. 46
      spring-test/src/test/java/org/springframework/test/web/reactive/server/samples/JsonContentTests.java

4
spring-test/src/main/java/org/springframework/test/web/reactive/server/DefaultWebTestClient.java

@ -659,10 +659,10 @@ class DefaultWebTestClient implements WebTestClient {
} }
@Override @Override
public BodyContentSpec json(String json) { public BodyContentSpec json(String json, boolean strict) {
this.result.assertWithDiagnostics(() -> { this.result.assertWithDiagnostics(() -> {
try { try {
new JsonExpectationsHelper().assertJsonEqual(json, getBodyAsString()); new JsonExpectationsHelper().assertJsonEqual(json, getBodyAsString(), strict);
} }
catch (Exception ex) { catch (Exception ex) {
throw new AssertionError("JSON parsing error", ex); throw new AssertionError("JSON parsing error", ex);

19
spring-test/src/main/java/org/springframework/test/web/reactive/server/WebTestClient.java

@ -979,7 +979,24 @@ public interface WebTestClient {
* on to be on the classpath. * on to be on the classpath.
* @param expectedJson the expected JSON content. * @param expectedJson the expected JSON content.
*/ */
BodyContentSpec json(String expectedJson); default BodyContentSpec json(String expectedJson) {
return json(expectedJson, false);
}
/**
* Parse the expected and actual response content as JSON and perform a
* comparison in two modes, depending on {@code strict} parameter value, verifying the same attribute-value pairs.
* <ul>
* <li>{@code true}: strict checking.
* <li>{@code false}: lenient checking.
* </ul>
* <p>Use of this option requires the
* <a href="https://jsonassert.skyscreamer.org/">JSONassert</a> library
* on to be on the classpath.
* @param expectedJson the expected JSON content.
* @param strict enables strict checking
*/
BodyContentSpec json(String expectedJson, boolean strict);
/** /**
* Parse expected and actual response content as XML and assert that * Parse expected and actual response content as XML and assert that

46
spring-test/src/test/java/org/springframework/test/web/reactive/server/samples/JsonContentTests.java

@ -31,10 +31,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 org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.containsString;
/** /**
* Samples of tests using {@link WebTestClient} with serialized JSON content. * Samples of tests using {@link WebTestClient} with serialized JSON content.
* *
@ -49,13 +49,32 @@ public class JsonContentTests {
@Test @Test
public void jsonContent() { public void jsonContent() {
this.client.get().uri("/persons") this.client.get().uri("/persons/extended")
.accept(MediaType.APPLICATION_JSON) .accept(MediaType.APPLICATION_JSON)
.exchange() .exchange()
.expectStatus().isOk() .expectStatus().isOk()
.expectBody().json("[{\"name\":\"Jane\"},{\"name\":\"Jason\"},{\"name\":\"John\"}]"); .expectBody().json("[{\"name\":\"Jane\"},{\"name\":\"Jason\"},{\"name\":\"John\"}]");
} }
@Test
public void jsonContentStrictFail() {
assertThatExceptionOfType(AssertionError.class).isThrownBy(() -> this.client.get().uri("/persons/extended")
.accept(MediaType.APPLICATION_JSON)
.exchange()
.expectStatus().isOk()
.expectBody().json("[{\"name\":\"Jane\"},{\"name\":\"Jason\"},{\"name\":\"John\"}]", true)
);
}
@Test
public void jsonContentStrict() {
this.client.get().uri("/persons/extended")
.accept(MediaType.APPLICATION_JSON)
.exchange()
.expectStatus().isOk()
.expectBody().json("[{\"name\":\"Jane\",\"surname\":\"Williams\"},{\"name\":\"Jason\",\"surname\":\"Johnson\"},{\"name\":\"John\",\"surname\":\"Smith\"}]", true);
}
@Test @Test
public void jsonPathIsEqualTo() { public void jsonPathIsEqualTo() {
this.client.get().uri("/persons") this.client.get().uri("/persons")
@ -98,6 +117,11 @@ public class JsonContentTests {
return Flux.just(new Person("Jane"), new Person("Jason"), new Person("John")); return Flux.just(new Person("Jane"), new Person("Jason"), new Person("John"));
} }
@GetMapping("/extended")
Flux<ExtendedPerson> getExtendedPersons() {
return Flux.just(new ExtendedPerson("Jane", "Williams"), new ExtendedPerson("Jason", "Johnson"), new ExtendedPerson("John", "Smith"));
}
@GetMapping("/{name}") @GetMapping("/{name}")
Person getPerson(@PathVariable String name) { Person getPerson(@PathVariable String name) {
return new Person(name); return new Person(name);
@ -109,4 +133,22 @@ public class JsonContentTests {
} }
} }
static class ExtendedPerson {
private String name;
private String surname;
public ExtendedPerson(String name, String surname) {
this.name = name;
this.surname = surname;
}
public String getName() {
return name;
}
public String getSurname() {
return surname;
}
}
} }

Loading…
Cancel
Save