diff --git a/spring-test/src/main/java/org/springframework/test/util/JsonExpectationsHelper.java b/spring-test/src/main/java/org/springframework/test/util/JsonExpectationsHelper.java index 4de0dba6eee..7c6489a6da0 100644 --- a/spring-test/src/main/java/org/springframework/test/util/JsonExpectationsHelper.java +++ b/spring-test/src/main/java/org/springframework/test/util/JsonExpectationsHelper.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 the original author or authors. + * Copyright 2002-2022 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. @@ -32,8 +32,8 @@ public class JsonExpectationsHelper { /** * Parse the expected and actual strings as JSON and assert the two * are "similar" - i.e. they contain the same attribute-value pairs - * regardless of formatting with a lenient checking (extensible, and non-strict - * array ordering). + * regardless of formatting with lenient checking (extensible content and + * non-strict array ordering). * @param expected the expected JSON content * @param actual the actual JSON content * @since 4.1 @@ -47,14 +47,14 @@ public class JsonExpectationsHelper { * Parse the expected and actual strings as JSON and assert the two * are "similar" - i.e. they contain the same attribute-value pairs * regardless of formatting. - *

Can compare in two modes, depending on {@code strict} parameter value: + *

Can compare in two modes, depending on the {@code strict} parameter value: *

* @param expected the expected JSON content * @param actual the actual JSON content - * @param strict enables strict checking + * @param strict enables strict checking if {@code true} * @since 4.2 */ public void assertJsonEqual(String expected, String actual, boolean strict) throws Exception { diff --git a/spring-test/src/main/java/org/springframework/test/web/reactive/server/DefaultWebTestClient.java b/spring-test/src/main/java/org/springframework/test/web/reactive/server/DefaultWebTestClient.java index 8628ef26226..a3cc4c2890e 100644 --- a/spring-test/src/main/java/org/springframework/test/web/reactive/server/DefaultWebTestClient.java +++ b/spring-test/src/main/java/org/springframework/test/web/reactive/server/DefaultWebTestClient.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2021 the original author or authors. + * Copyright 2002-2022 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. @@ -659,10 +659,10 @@ class DefaultWebTestClient implements WebTestClient { } @Override - public BodyContentSpec json(String json) { + public BodyContentSpec json(String json, boolean strict) { this.result.assertWithDiagnostics(() -> { try { - new JsonExpectationsHelper().assertJsonEqual(json, getBodyAsString()); + new JsonExpectationsHelper().assertJsonEqual(json, getBodyAsString(), strict); } catch (Exception ex) { throw new AssertionError("JSON parsing error", ex); diff --git a/spring-test/src/main/java/org/springframework/test/web/reactive/server/WebTestClient.java b/spring-test/src/main/java/org/springframework/test/web/reactive/server/WebTestClient.java index 141428f171a..481a8d999e8 100644 --- a/spring-test/src/main/java/org/springframework/test/web/reactive/server/WebTestClient.java +++ b/spring-test/src/main/java/org/springframework/test/web/reactive/server/WebTestClient.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2021 the original author or authors. + * Copyright 2002-2022 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. @@ -973,13 +973,37 @@ public interface WebTestClient { /** * Parse the expected and actual response content as JSON and perform a - * "lenient" comparison verifying the same attribute-value pairs. - *

Use of this option requires the + * comparison verifying that they contain the same attribute-value pairs + * regardless of formatting with lenient checking (extensible + * and non-strict array ordering). + *

Use of this method requires the + * JSONassert library + * to be on the classpath. + * @param expectedJson the expected JSON content + * @see #json(String, boolean) + */ + default BodyContentSpec json(String expectedJson) { + return json(expectedJson, false); + } + + /** + * Parse the expected and actual response content as JSON and perform a + * comparison verifying that they contain the same attribute-value pairs + * regardless of formatting. + *

Can compare in two modes, depending on the {@code strict} parameter value: + *

+ *

Use of this method requires the * JSONassert library - * on to be on the classpath. - * @param expectedJson the expected JSON content. + * to be on the classpath. + * @param expectedJson the expected JSON content + * @param strict enables strict checking if {@code true} + * @since 5.3.16 + * @see #json(String) */ - BodyContentSpec json(String expectedJson); + BodyContentSpec json(String expectedJson, boolean strict); /** * Parse expected and actual response content as XML and assert that diff --git a/spring-test/src/test/java/org/springframework/test/web/reactive/server/samples/ErrorTests.java b/spring-test/src/test/java/org/springframework/test/web/reactive/server/samples/ErrorTests.java index f2637bc1709..89a06defd64 100644 --- a/spring-test/src/test/java/org/springframework/test/web/reactive/server/samples/ErrorTests.java +++ b/spring-test/src/test/java/org/springframework/test/web/reactive/server/samples/ErrorTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2022 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. @@ -37,13 +37,13 @@ import static org.assertj.core.api.Assertions.assertThat; * @author Rossen Stoyanchev * @since 5.0 */ -public class ErrorTests { +class ErrorTests { private final WebTestClient client = WebTestClient.bindToController(new TestController()).build(); @Test - public void notFound(){ + void notFound(){ this.client.get().uri("/invalid") .exchange() .expectStatus().isNotFound() @@ -51,7 +51,7 @@ public class ErrorTests { } @Test - public void serverException() { + void serverException() { this.client.get().uri("/server-error") .exchange() .expectStatus().isEqualTo(HttpStatus.INTERNAL_SERVER_ERROR) @@ -59,7 +59,7 @@ public class ErrorTests { } @Test // SPR-17363 - public void badRequestBeforeRequestBodyConsumed() { + void badRequestBeforeRequestBodyConsumed() { EntityExchangeResult result = this.client.post() .uri("/post") .contentType(MediaType.APPLICATION_JSON) diff --git a/spring-test/src/test/java/org/springframework/test/web/reactive/server/samples/ExchangeMutatorTests.java b/spring-test/src/test/java/org/springframework/test/web/reactive/server/samples/ExchangeMutatorTests.java index d5dbbd597ce..759770bf652 100644 --- a/spring-test/src/test/java/org/springframework/test/web/reactive/server/samples/ExchangeMutatorTests.java +++ b/spring-test/src/test/java/org/springframework/test/web/reactive/server/samples/ExchangeMutatorTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2017 the original author or authors. + * Copyright 2002-2022 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. @@ -18,7 +18,6 @@ package org.springframework.test.web.reactive.server.samples; import java.security.Principal; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import reactor.core.publisher.Mono; @@ -37,23 +36,18 @@ import org.springframework.web.server.adapter.WebHttpHandlerBuilder; /** * Samples tests that demonstrate applying ServerWebExchange initialization. + * * @author Rossen Stoyanchev */ -public class ExchangeMutatorTests { - - private WebTestClient webTestClient; +class ExchangeMutatorTests { + private final WebTestClient webTestClient = WebTestClient.bindToController(new TestController()) + .apply(identity("Pablo")) + .build(); - @BeforeEach - public void setUp() throws Exception { - - this.webTestClient = WebTestClient.bindToController(new TestController()) - .apply(identity("Pablo")) - .build(); - } @Test - public void useGloballyConfiguredIdentity() throws Exception { + void useGloballyConfiguredIdentity() { this.webTestClient.get().uri("/userIdentity") .exchange() .expectStatus().isOk() @@ -61,8 +55,7 @@ public class ExchangeMutatorTests { } @Test - public void useLocallyConfiguredIdentity() throws Exception { - + void useLocallyConfiguredIdentity() { this.webTestClient .mutateWith(identity("Giovanni")) .get().uri("/userIdentity") diff --git a/spring-test/src/test/java/org/springframework/test/web/reactive/server/samples/GlobalEntityResultConsumerTests.java b/spring-test/src/test/java/org/springframework/test/web/reactive/server/samples/GlobalEntityResultConsumerTests.java index 24bf92ecbb3..1a68d62ca1c 100644 --- a/spring-test/src/test/java/org/springframework/test/web/reactive/server/samples/GlobalEntityResultConsumerTests.java +++ b/spring-test/src/test/java/org/springframework/test/web/reactive/server/samples/GlobalEntityResultConsumerTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2021 the original author or authors. + * Copyright 2002-2022 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. @@ -96,4 +96,5 @@ public class GlobalEntityResultConsumerTests { return Arrays.asList(new Person("Joe"), new Person("Joseph")); } } + } diff --git a/spring-test/src/test/java/org/springframework/test/web/reactive/server/samples/HeaderAndCookieTests.java b/spring-test/src/test/java/org/springframework/test/web/reactive/server/samples/HeaderAndCookieTests.java index e42dff7c110..a2b743c6425 100644 --- a/spring-test/src/test/java/org/springframework/test/web/reactive/server/samples/HeaderAndCookieTests.java +++ b/spring-test/src/test/java/org/springframework/test/web/reactive/server/samples/HeaderAndCookieTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2017 the original author or authors. + * Copyright 2002-2022 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. @@ -29,16 +29,17 @@ import org.springframework.web.bind.annotation.RestController; /** * Tests with headers and cookies. + * * @author Rossen Stoyanchev * @since 5.0 */ -public class HeaderAndCookieTests { +class HeaderAndCookieTests { private final WebTestClient client = WebTestClient.bindToController(new TestController()).build(); @Test - public void requestResponseHeaderPair() throws Exception { + void requestResponseHeaderPair() { this.client.get().uri("/header-echo").header("h1", "in") .exchange() .expectStatus().isOk() @@ -46,7 +47,7 @@ public class HeaderAndCookieTests { } @Test - public void headerMultipleValues() throws Exception { + void headerMultipleValues() { this.client.get().uri("/header-multi-value") .exchange() .expectStatus().isOk() @@ -54,7 +55,7 @@ public class HeaderAndCookieTests { } @Test - public void setCookies() { + void setCookies() { this.client.get().uri("/cookie-echo") .cookies(cookies -> cookies.add("k1", "v1")) .exchange() diff --git a/spring-test/src/test/java/org/springframework/test/web/reactive/server/samples/JsonContentTests.java b/spring-test/src/test/java/org/springframework/test/web/reactive/server/samples/JsonContentTests.java index 82d271c8777..e6a4ed77995 100644 --- a/spring-test/src/test/java/org/springframework/test/web/reactive/server/samples/JsonContentTests.java +++ b/spring-test/src/test/java/org/springframework/test/web/reactive/server/samples/JsonContentTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2022 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. @@ -31,10 +31,9 @@ import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; import static org.hamcrest.Matchers.containsString; - - /** * Samples of tests using {@link WebTestClient} with serialized JSON content. * @@ -42,47 +41,76 @@ import static org.hamcrest.Matchers.containsString; * @author Sam Brannen * @since 5.0 */ -public class JsonContentTests { +class JsonContentTests { private final WebTestClient client = WebTestClient.bindToController(new PersonController()).build(); @Test - public void jsonContent() { + void jsonContentWithDefaultLenientMode() { + this.client.get().uri("/persons") + .accept(MediaType.APPLICATION_JSON) + .exchange() + .expectStatus().isOk() + .expectBody().json( + "[{\"firstName\":\"Jane\"}," + + "{\"firstName\":\"Jason\"}," + + "{\"firstName\":\"John\"}]"); + } + + @Test + void jsonContentWithStrictMode() { this.client.get().uri("/persons") .accept(MediaType.APPLICATION_JSON) .exchange() .expectStatus().isOk() - .expectBody().json("[{\"name\":\"Jane\"},{\"name\":\"Jason\"},{\"name\":\"John\"}]"); + .expectBody().json( + "[{\"firstName\":\"Jane\",\"lastName\":\"Williams\"}," + + "{\"firstName\":\"Jason\",\"lastName\":\"Johnson\"}," + + "{\"firstName\":\"John\",\"lastName\":\"Smith\"}]", + true); + } + + @Test + void jsonContentWithStrictModeAndMissingAttributes() { + assertThatExceptionOfType(AssertionError.class).isThrownBy(() -> this.client.get().uri("/persons") + .accept(MediaType.APPLICATION_JSON) + .exchange() + .expectBody().json( + "[{\"firstName\":\"Jane\"}," + + "{\"firstName\":\"Jason\"}," + + "{\"firstName\":\"John\"}]", + true) + ); } @Test - public void jsonPathIsEqualTo() { + void jsonPathIsEqualTo() { this.client.get().uri("/persons") .accept(MediaType.APPLICATION_JSON) .exchange() .expectStatus().isOk() .expectBody() - .jsonPath("$[0].name").isEqualTo("Jane") - .jsonPath("$[1].name").isEqualTo("Jason") - .jsonPath("$[2].name").isEqualTo("John"); + .jsonPath("$[0].firstName").isEqualTo("Jane") + .jsonPath("$[1].firstName").isEqualTo("Jason") + .jsonPath("$[2].firstName").isEqualTo("John"); } @Test - public void jsonPathMatches() { - this.client.get().uri("/persons/John") + void jsonPathMatches() { + this.client.get().uri("/persons/John/Smith") .accept(MediaType.APPLICATION_JSON) .exchange() .expectStatus().isOk() .expectBody() - .jsonPath("$.name").value(containsString("oh")); + .jsonPath("$.firstName").value(containsString("oh")); } @Test - public void postJsonContent() { + void postJsonContent() { this.client.post().uri("/persons") .contentType(MediaType.APPLICATION_JSON) - .bodyValue("{\"name\":\"John\"}") + .bodyValue("{\"firstName\":\"John\",\"lastName\":\"Smith\"}") .exchange() .expectStatus().isCreated() .expectBody().isEmpty(); @@ -95,17 +123,38 @@ public class JsonContentTests { @GetMapping Flux getPersons() { - return Flux.just(new Person("Jane"), new Person("Jason"), new Person("John")); + return Flux.just(new Person("Jane", "Williams"), new Person("Jason", "Johnson"), new Person("John", "Smith")); } - @GetMapping("/{name}") - Person getPerson(@PathVariable String name) { - return new Person(name); + @GetMapping("/{firstName}/{lastName}") + Person getPerson(@PathVariable String firstName, @PathVariable String lastName) { + return new Person(firstName, lastName); } @PostMapping ResponseEntity savePerson(@RequestBody Person person) { - return ResponseEntity.created(URI.create("/persons/" + person.getName())).build(); + return ResponseEntity.created(URI.create(String.format("/persons/%s/%s", person.getFirstName(), person.getLastName()))).build(); + } + } + + static class Person { + private String firstName; + private String lastName; + + public Person() { + } + + public Person(String firstName, String lastName) { + this.firstName = firstName; + this.lastName = lastName; + } + + public String getFirstName() { + return this.firstName; + } + + public String getLastName() { + return this.lastName; } } diff --git a/spring-test/src/test/java/org/springframework/test/web/reactive/server/samples/ResponseEntityTests.java b/spring-test/src/test/java/org/springframework/test/web/reactive/server/samples/ResponseEntityTests.java index 3acbf66d984..f1619d61881 100644 --- a/spring-test/src/test/java/org/springframework/test/web/reactive/server/samples/ResponseEntityTests.java +++ b/spring-test/src/test/java/org/springframework/test/web/reactive/server/samples/ResponseEntityTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2022 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. @@ -49,7 +49,7 @@ import static org.springframework.http.MediaType.TEXT_EVENT_STREAM; * @author Rossen Stoyanchev * @since 5.0 */ -public class ResponseEntityTests { +class ResponseEntityTests { private final WebTestClient client = WebTestClient.bindToController(new PersonController()) .configureClient() @@ -58,7 +58,7 @@ public class ResponseEntityTests { @Test - public void entity() { + void entity() { this.client.get().uri("/John") .exchange() .expectStatus().isOk() @@ -67,7 +67,7 @@ public class ResponseEntityTests { } @Test - public void entityMatcher() { + void entityMatcher() { this.client.get().uri("/John") .exchange() .expectStatus().isOk() @@ -76,7 +76,7 @@ public class ResponseEntityTests { } @Test - public void entityWithConsumer() { + void entityWithConsumer() { this.client.get().uri("/John") .exchange() .expectStatus().isOk() @@ -86,8 +86,7 @@ public class ResponseEntityTests { } @Test - public void entityList() { - + void entityList() { List expected = Arrays.asList( new Person("Jane"), new Person("Jason"), new Person("John")); @@ -99,8 +98,7 @@ public class ResponseEntityTests { } @Test - public void entityListWithConsumer() { - + void entityListWithConsumer() { this.client.get() .exchange() .expectStatus().isOk() @@ -111,8 +109,7 @@ public class ResponseEntityTests { } @Test - public void entityMap() { - + void entityMap() { Map map = new LinkedHashMap<>(); map.put("Jane", new Person("Jane")); map.put("Jason", new Person("Jason")); @@ -125,8 +122,7 @@ public class ResponseEntityTests { } @Test - public void entityStream() { - + void entityStream() { FluxExchangeResult result = this.client.get() .accept(TEXT_EVENT_STREAM) .exchange() @@ -143,7 +139,7 @@ public class ResponseEntityTests { } @Test - public void postEntity() { + void postEntity() { this.client.post() .bodyValue(new Person("John")) .exchange() diff --git a/spring-test/src/test/java/org/springframework/test/web/reactive/server/samples/XmlContentTests.java b/spring-test/src/test/java/org/springframework/test/web/reactive/server/samples/XmlContentTests.java index fef7d629a2b..c913d323522 100644 --- a/spring-test/src/test/java/org/springframework/test/web/reactive/server/samples/XmlContentTests.java +++ b/spring-test/src/test/java/org/springframework/test/web/reactive/server/samples/XmlContentTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2022 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. @@ -40,15 +40,13 @@ import org.springframework.web.bind.annotation.RestController; import static org.hamcrest.Matchers.startsWith; - - /** * Samples of tests using {@link WebTestClient} with XML content. * * @author Eric Deandrea * @since 5.1 */ -public class XmlContentTests { +class XmlContentTests { private static final String persons_XML = "" @@ -63,7 +61,7 @@ public class XmlContentTests { @Test - public void xmlContent() { + void xmlContent() { this.client.get().uri("/persons") .accept(MediaType.APPLICATION_XML) .exchange() @@ -72,7 +70,7 @@ public class XmlContentTests { } @Test - public void xpathIsEqualTo() { + void xpathIsEqualTo() { this.client.get().uri("/persons") .accept(MediaType.APPLICATION_XML) .exchange() @@ -88,7 +86,7 @@ public class XmlContentTests { } @Test - public void xpathMatches() { + void xpathMatches() { this.client.get().uri("/persons") .accept(MediaType.APPLICATION_XML) .exchange() @@ -98,7 +96,7 @@ public class XmlContentTests { } @Test - public void xpathContainsSubstringViaRegex() { + void xpathContainsSubstringViaRegex() { this.client.get().uri("/persons/John") .accept(MediaType.APPLICATION_XML) .exchange() @@ -108,8 +106,7 @@ public class XmlContentTests { } @Test - public void postXmlContent() { - + void postXmlContent() { String content = "" + "John";