Add AssertJ support for HTTP requests and responses

This commit adds AssertJ compatible assertions for HTTP request and
responses, including headers, media type, and response body. The latter
delegate to the recently included JSON assert support.

See gh-21178
This commit is contained in:
Stéphane Nicoll
2024-03-15 13:22:15 +01:00
parent 76f45c4289
commit e97ae434fb
18 changed files with 1863 additions and 0 deletions

View File

@@ -0,0 +1,190 @@
/*
* 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.http;
import java.time.Instant;
import java.util.List;
import java.util.Map;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.http.HttpHeaders;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
/**
* Tests for {@link HttpHeadersAssert}.
*
* @author Stephane Nicoll
*/
class HttpHeadersAssertTests {
@Test
void containsHeader() {
assertThat(Map.of("first", "1")).containsHeader("first");
}
@Test
void containsHeaderWithNameNotPresent() {
Map<String, String> map = Map.of("first", "1");
Assertions.assertThatExceptionOfType(AssertionError.class)
.isThrownBy(() -> assertThat(map).containsHeader("wrong-name"))
.withMessageContainingAll("HTTP headers", "first", "wrong-name");
}
@Test
void containsHeaders() {
assertThat(Map.of("first", "1", "second", "2", "third", "3"))
.containsHeaders("first", "third");
}
@Test
void containsHeadersWithSeveralNamesNotPresent() {
Map<String, String> map = Map.of("first", "1", "second", "2", "third", "3");
Assertions.assertThatExceptionOfType(AssertionError.class)
.isThrownBy(() -> assertThat(map).containsHeaders("first", "wrong-name", "another-wrong-name", "third"))
.withMessageContainingAll("HTTP headers", "first", "wrong-name", "another-wrong-name");
}
@Test
void doesNotContainsHeader() {
assertThat(Map.of("first", "1")).doesNotContainsHeader("second");
}
@Test
void doesNotContainsHeaderWithNamePresent() {
Map<String, String> map = Map.of("first", "1");
Assertions.assertThatExceptionOfType(AssertionError.class)
.isThrownBy(() -> assertThat(map).doesNotContainKey("first"))
.withMessageContainingAll("HTTP headers", "first");
}
@Test
void doesNotContainsHeaders() {
assertThat(Map.of("first", "1", "third", "3"))
.doesNotContainsHeaders("second", "fourth");
}
@Test
void doesNotContainsHeadersWithSeveralNamesPresent() {
Map<String, String> map = Map.of("first", "1", "second", "2", "third", "3");
Assertions.assertThatExceptionOfType(AssertionError.class)
.isThrownBy(() -> assertThat(map).doesNotContainsHeaders("first", "another-wrong-name", "second"))
.withMessageContainingAll("HTTP headers", "first", "second");
}
@Test
void hasValueWithStringMatch() {
HttpHeaders headers = new HttpHeaders();
headers.addAll("header", List.of("a", "b", "c"));
assertThat(headers).hasValue("header", "a");
}
@Test
void hasValueWithStringMatchOnSecondaryValue() {
HttpHeaders headers = new HttpHeaders();
headers.addAll("header", List.of("first", "second", "third"));
Assertions.assertThatExceptionOfType(AssertionError.class)
.isThrownBy(() -> assertThat(headers).hasValue("header", "second"))
.withMessageContainingAll("check primary value for HTTP header 'header'", "first", "second");
}
@Test
void hasValueWithNoStringMatch() {
HttpHeaders headers = new HttpHeaders();
headers.addAll("header", List.of("first", "second", "third"));
Assertions.assertThatExceptionOfType(AssertionError.class)
.isThrownBy(() -> assertThat(headers).hasValue("wrong-name", "second"))
.withMessageContainingAll("HTTP headers", "header", "wrong-name");
}
@Test
void hasValueWithNonPresentHeader() {
HttpHeaders map = new HttpHeaders();
map.add("test-header", "a");
Assertions.assertThatExceptionOfType(AssertionError.class)
.isThrownBy(() -> assertThat(map).hasValue("wrong-name", "a"))
.withMessageContainingAll("HTTP headers", "test-header", "wrong-name");
}
@Test
void hasValueWithLongMatch() {
HttpHeaders headers = new HttpHeaders();
headers.addAll("header", List.of("123", "456", "789"));
assertThat(headers).hasValue("header", 123);
}
@Test
void hasValueWithLongMatchOnSecondaryValue() {
HttpHeaders map = new HttpHeaders();
map.addAll("header", List.of("123", "456", "789"));
Assertions.assertThatExceptionOfType(AssertionError.class)
.isThrownBy(() -> assertThat(map).hasValue("header", 456))
.withMessageContainingAll("check primary long value for HTTP header 'header'", "123", "456");
}
@Test
void hasValueWithNoLongMatch() {
HttpHeaders map = new HttpHeaders();
map.addAll("header", List.of("123", "456", "789"));
Assertions.assertThatExceptionOfType(AssertionError.class)
.isThrownBy(() -> assertThat(map).hasValue("wrong-name", 456))
.withMessageContainingAll("HTTP headers", "header", "wrong-name");
}
@Test
void hasValueWithInstantMatch() {
Instant instant = Instant.now();
HttpHeaders headers = new HttpHeaders();
headers.setInstant("header", instant);
assertThat(headers).hasValue("header", instant);
}
@Test
void hasValueWithNoInstantMatch() {
Instant instant = Instant.now();
HttpHeaders map = new HttpHeaders();
map.setInstant("header", instant);
Assertions.assertThatExceptionOfType(AssertionError.class)
.isThrownBy(() -> assertThat(map).hasValue("wrong-name", instant.minusSeconds(30)))
.withMessageContainingAll("HTTP headers", "header", "wrong-name");
}
@Test
void hasValueWithNoInstantMatchOneSecOfDifference() {
Instant instant = Instant.now();
HttpHeaders map = new HttpHeaders();
map.setInstant("header", instant);
Assertions.assertThatExceptionOfType(AssertionError.class)
.isThrownBy(() -> assertThat(map).hasValue("wrong-name", instant.minusSeconds(1)))
.withMessageContainingAll("HTTP headers", "header", "wrong-name");
}
private static HttpHeadersAssert assertThat(Map<String, String> values) {
MultiValueMap<String, String> map = new LinkedMultiValueMap<>();
values.forEach(map::add);
return assertThat(new HttpHeaders(map));
}
private static HttpHeadersAssert assertThat(HttpHeaders values) {
return new HttpHeadersAssert(values);
}
}

View File

@@ -0,0 +1,157 @@
/*
* 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.http;
import org.junit.jupiter.api.Test;
import org.springframework.http.MediaType;
import org.springframework.lang.Nullable;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
/**
* Tests for {@link MediaTypeAssert}.
*
* @author Brian Clozel
* @author Stephane Nicoll
*/
class MediaTypeAssertTests {
@Test
void actualCanBeNull() {
new MediaTypeAssert((MediaType) null).isNull();
}
@Test
void actualStringCanBeNull() {
new MediaTypeAssert((String) null).isNull();
}
@Test
void isEqualWhenSameShouldPass() {
assertThat(mediaType("application/json")).isEqualTo("application/json");
}
@Test
void isEqualWhenDifferentShouldFail() {
assertThatExceptionOfType(AssertionError.class)
.isThrownBy(() -> assertThat(mediaType("application/json")).isEqualTo("text/html"))
.withMessageContaining("Media type");
}
@Test
void isEqualWhenActualIsNullShouldFail() {
assertThatExceptionOfType(AssertionError.class)
.isThrownBy(() -> assertThat(null).isEqualTo(MediaType.APPLICATION_JSON))
.withMessageContaining("Media type");
}
@Test
void isEqualWhenSameTypeShouldPass() {
assertThat(mediaType("application/json")).isEqualTo(MediaType.APPLICATION_JSON);
}
@Test
void isEqualWhenDifferentTypeShouldFail() {
assertThatExceptionOfType(AssertionError.class)
.isThrownBy(() -> assertThat(mediaType("application/json")).isEqualTo(MediaType.TEXT_HTML))
.withMessageContaining("Media type");
}
@Test
void isCompatibleWhenSameShouldPass() {
assertThat(mediaType("application/json")).isCompatibleWith("application/json");
}
@Test
void isCompatibleWhenCompatibleShouldPass() {
assertThat(mediaType("application/json")).isCompatibleWith("application/*");
}
@Test
void isCompatibleWhenDifferentShouldFail() {
assertThatExceptionOfType(AssertionError.class)
.isThrownBy(() -> assertThat(mediaType("application/json")).isCompatibleWith("text/html"))
.withMessageContaining("check media type 'application/json' is compatible with 'text/html'");
}
@Test
void isCompatibleWithStringAndNullActual() {
assertThatExceptionOfType(AssertionError.class)
.isThrownBy(() -> assertThat(null).isCompatibleWith("text/html"))
.withMessageContaining("Expecting null to be compatible with 'text/html'");
}
@Test
void isCompatibleWithStringAndNullExpected() {
assertThatExceptionOfType(AssertionError.class)
.isThrownBy(() -> assertThat(mediaType("application/json")).isCompatibleWith((String) null))
.withMessageContainingAll("Expecting:", "null", "To be a valid media type but got:",
"'mimeType' must not be empty");
}
@Test
void isCompatibleWithStringAndEmptyExpected() {
assertThatExceptionOfType(AssertionError.class)
.isThrownBy(() -> assertThat(mediaType("application/json")).isCompatibleWith(""))
.withMessageContainingAll("Expecting:", "", "To be a valid media type but got:",
"'mimeType' must not be empty");
}
@Test
void isCompatibleWithMediaTypeAndNullActual() {
assertThatExceptionOfType(AssertionError.class)
.isThrownBy(() -> assertThat(null).isCompatibleWith(MediaType.TEXT_HTML))
.withMessageContaining("Expecting null to be compatible with 'text/html'");
}
@Test
void isCompatibleWithMediaTypeAndNullExpected() {
assertThatExceptionOfType(AssertionError.class)
.isThrownBy(() -> assertThat(mediaType("application/json")).isCompatibleWith((MediaType) null))
.withMessageContaining("Expecting 'application/json' to be compatible with null");
}
@Test
void isCompatibleWhenSameTypeShouldPass() {
assertThat(mediaType("application/json")).isCompatibleWith(MediaType.APPLICATION_JSON);
}
@Test
void isCompatibleWhenCompatibleTypeShouldPass() {
assertThat(mediaType("application/json")).isCompatibleWith(MediaType.parseMediaType("application/*"));
}
@Test
void isCompatibleWhenDifferentTypeShouldFail() {
assertThatExceptionOfType(AssertionError.class)
.isThrownBy(() -> assertThat(mediaType("application/json")).isCompatibleWith(MediaType.TEXT_HTML))
.withMessageContaining("check media type 'application/json' is compatible with 'text/html'");
}
@Nullable
private static MediaType mediaType(@Nullable String mediaType) {
return (mediaType != null ? MediaType.parseMediaType(mediaType) : null);
}
private static MediaTypeAssert assertThat(@Nullable MediaType mediaType) {
return new MediaTypeAssert(mediaType);
}
}

View File

@@ -0,0 +1,77 @@
/*
* 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;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
/**
* Tests for {@link UriAssert}.
*
* @author Stephane Nicoll
*/
class UriAssertTests {
@Test
void isEqualToTemplate() {
assertThat("/orders/1/items/2").isEqualToTemplate("/orders/{orderId}/items/{itemId}", 1, 2);
}
@Test
void isEqualToTemplateWithWrongValue() {
String expected = "/orders/1/items/3";
String actual = "/orders/1/items/2";
assertThatExceptionOfType(AssertionError.class)
.isThrownBy(() -> assertThat(expected).isEqualToTemplate("/orders/{orderId}/items/{itemId}", 1, 2))
.withMessageContainingAll("Test URI", expected, actual);
}
@Test
void isEqualToTemplateMissingArg() {
String template = "/orders/{orderId}/items/{itemId}";
assertThatExceptionOfType(AssertionError.class)
.isThrownBy(() -> assertThat("/orders/1/items/2").isEqualToTemplate(template, 1))
.withMessageContainingAll("Expecting:", template,
"Not enough variable values available to expand 'itemId'");
}
@Test
void matchPattern() {
assertThat("/orders/1").matchPattern("/orders/*");
}
@Test
void matchPatternWithNonValidPattern() {
assertThatExceptionOfType(AssertionError.class)
.isThrownBy(() -> assertThat("/orders/1").matchPattern("/orders/"))
.withMessage("'/orders/' is not an Ant-style path pattern");
}
@Test
void matchPatternWithWrongValue() {
assertThatExceptionOfType(AssertionError.class)
.isThrownBy(() -> assertThat("/orders/1").matchPattern("/resources/*"))
.withMessageContainingAll("Test URI", "/resources/*", "/orders/1");
}
UriAssert assertThat(String uri) {
return new UriAssert(uri, "Test URI");
}
}

View File

@@ -0,0 +1,143 @@
/*
* 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.util.LinkedHashMap;
import java.util.Map;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpSession;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.springframework.mock.web.MockHttpServletRequest;
import static java.util.Map.entry;
/**
* Tests for {@link AbstractHttpServletRequestAssert}.
*
* @author Stephane Nicoll
*/
public class AbstractHttpServletRequestAssertTests {
@Nested
class AttributesTests {
@Test
void attributesAreCopied() {
Map<String, Object> map = new LinkedHashMap<>();
map.put("one", 1);
map.put("two", 2);
assertThat(createRequest(map)).attributes()
.containsExactly(entry("one", 1), entry("two", 2));
}
@Test
void attributesWithWrongKey() {
HttpServletRequest request = createRequest(Map.of("one", 1));
Assertions.assertThatExceptionOfType(AssertionError.class)
.isThrownBy(() -> assertThat(request).attributes().containsKey("two"))
.withMessageContainingAll("Request Attributes", "two", "one");
}
private HttpServletRequest createRequest(Map<String, Object> attributes) {
MockHttpServletRequest request = new MockHttpServletRequest();
attributes.forEach(request::setAttribute);
return request;
}
}
@Nested
class SessionAttributesTests {
@Test
void sessionAttributesAreCopied() {
Map<String, Object> map = new LinkedHashMap<>();
map.put("one", 1);
map.put("two", 2);
assertThat(createRequest(map)).sessionAttributes()
.containsExactly(entry("one", 1), entry("two", 2));
}
@Test
void sessionAttributesWithWrongKey() {
HttpServletRequest request = createRequest(Map.of("one", 1));
Assertions.assertThatExceptionOfType(AssertionError.class)
.isThrownBy(() -> assertThat(request).sessionAttributes().containsKey("two"))
.withMessageContainingAll("Session Attributes", "two", "one");
}
private HttpServletRequest createRequest(Map<String, Object> attributes) {
MockHttpServletRequest request = new MockHttpServletRequest();
HttpSession session = request.getSession();
Assertions.assertThat(session).isNotNull();
attributes.forEach(session::setAttribute);
return request;
}
}
@Test
void hasAsyncStartedTrue() {
MockHttpServletRequest request = new MockHttpServletRequest();
request.setAsyncStarted(true);
assertThat(request).hasAsyncStarted(true);
}
@Test
void hasAsyncStartedTrueWithFalse() {
MockHttpServletRequest request = new MockHttpServletRequest();
request.setAsyncStarted(false);
Assertions.assertThatExceptionOfType(AssertionError.class)
.isThrownBy(() -> assertThat(request).hasAsyncStarted(true))
.withMessage("Async expected to have started");
}
@Test
void hasAsyncStartedFalse() {
MockHttpServletRequest request = new MockHttpServletRequest();
request.setAsyncStarted(false);
assertThat(request).hasAsyncStarted(false);
}
@Test
void hasAsyncStartedFalseWithTrue() {
MockHttpServletRequest request = new MockHttpServletRequest();
request.setAsyncStarted(true);
Assertions.assertThatExceptionOfType(AssertionError.class)
.isThrownBy(() -> assertThat(request).hasAsyncStarted(false))
.withMessage("Async expected to not have started");
}
private static ResponseAssert assertThat(HttpServletRequest response) {
return new ResponseAssert(response);
}
private static final class ResponseAssert extends AbstractHttpServletRequestAssert<ResponseAssert, HttpServletRequest> {
ResponseAssert(HttpServletRequest actual) {
super(actual, ResponseAssert.class);
}
}
}

View File

@@ -0,0 +1,138 @@
/*
* 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.util.Map;
import jakarta.servlet.http.HttpServletResponse;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.springframework.http.HttpStatus;
import org.springframework.mock.web.MockHttpServletResponse;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
/**
* Tests for {@link AbstractHttpServletResponseAssert}.
*
* @author Stephane Nicoll
*/
class AbstractHttpServletResponseAssertTests {
@Nested
class HeadersTests {
@Test
void headersAreMatching() {
MockHttpServletResponse response = createResponse(Map.of("n1", "v1", "n2", "v2", "n3", "v3"));
assertThat(response).headers().containsHeaders("n1", "n2", "n3");
}
private MockHttpServletResponse createResponse(Map<String, String> headers) {
MockHttpServletResponse response = new MockHttpServletResponse();
headers.forEach(response::addHeader);
return response;
}
}
@Nested
class StatusTests {
@Test
void hasStatusWithCode() {
assertThat(createResponse(200)).hasStatus(200);
}
@Test
void hasStatusWithHttpStatus() {
assertThat(createResponse(200)).hasStatus(HttpStatus.OK);
}
@Test
void hasStatusOK() {
assertThat(createResponse(200)).hasStatusOk();
}
@Test
void hasStatusWithWrongCode() {
MockHttpServletResponse response = createResponse(200);
assertThatExceptionOfType(AssertionError.class).isThrownBy(() -> assertThat(response).hasStatus(300))
.withMessageContainingAll("HTTP status code", "200", "300");
}
@Test
void hasStatus1xxInformational() {
assertThat(createResponse(199)).hasStatus1xxInformational();
}
@Test
void hasStatus2xxSuccessful() {
assertThat(createResponse(299)).hasStatus2xxSuccessful();
}
@Test
void hasStatus3xxRedirection() {
assertThat(createResponse(399)).hasStatus3xxRedirection();
}
@Test
void hasStatus4xxClientError() {
assertThat(createResponse(499)).hasStatus4xxClientError();
}
@Test
void hasStatus5xxServerError() {
assertThat(createResponse(599)).hasStatus5xxServerError();
}
@Test
void hasStatusWithWrongSeries() {
MockHttpServletResponse response = createResponse(500);
assertThatExceptionOfType(AssertionError.class)
.isThrownBy(() -> assertThat(response).hasStatus2xxSuccessful())
.withMessageContainingAll("HTTP status series", "SUCCESSFUL", "SERVER_ERROR");
}
private MockHttpServletResponse createResponse(int status) {
MockHttpServletResponse response = new MockHttpServletResponse();
response.setStatus(status);
return response;
}
}
private static ResponseAssert assertThat(HttpServletResponse response) {
return new ResponseAssert(response);
}
private static final class ResponseAssert extends AbstractHttpServletResponseAssert<HttpServletResponse, ResponseAssert, HttpServletResponse> {
ResponseAssert(HttpServletResponse actual) {
super(actual, ResponseAssert.class);
}
@Override
protected HttpServletResponse getResponse() {
return this.actual;
}
}
}

View File

@@ -0,0 +1,48 @@
/*
* 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 org.junit.jupiter.api.Test;
import org.springframework.mock.web.MockHttpServletRequest;
/**
* Tests for {@link AbstractMockHttpServletRequestAssert}.
*
* @author Stephane Nicoll
*/
class AbstractMockHttpServletRequestAssertTests {
@Test
void requestCanBeAsserted() {
MockHttpServletRequest request = new MockHttpServletRequest();
assertThat(request).satisfies(actual -> assertThat(actual).isSameAs(request));
}
private static RequestAssert assertThat(MockHttpServletRequest request) {
return new RequestAssert(request);
}
private static final class RequestAssert extends AbstractMockHttpServletRequestAssert<RequestAssert> {
RequestAssert(MockHttpServletRequest actual) {
super(actual, RequestAssert.class);
}
}
}

View File

@@ -0,0 +1,106 @@
/*
* 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.StandardCharsets;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.http.HttpHeaders;
import org.springframework.mock.web.MockHttpServletResponse;
/**
* Tests for {@link AbstractMockHttpServletResponseAssert}.
*
* @author Stephane Nicoll
*/
public class AbstractMockHttpServletResponseAssertTests {
@Test
void hasForwardedUrl() {
String forwardedUrl = "https://example.com/42";
MockHttpServletResponse response = new MockHttpServletResponse();
response.setForwardedUrl(forwardedUrl);
assertThat(response).hasForwardedUrl(forwardedUrl);
}
@Test
void hasForwardedUrlWithWrongValue() {
String forwardedUrl = "https://example.com/42";
MockHttpServletResponse response = new MockHttpServletResponse();
response.setForwardedUrl(forwardedUrl);
Assertions.assertThatExceptionOfType(AssertionError.class)
.isThrownBy(() -> assertThat(response).hasForwardedUrl("another"))
.withMessageContainingAll("Forwarded URL", forwardedUrl, "another");
}
@Test
void hasRedirectedUrl() {
String redirectedUrl = "https://example.com/42";
MockHttpServletResponse response = new MockHttpServletResponse();
response.addHeader(HttpHeaders.LOCATION, redirectedUrl);
assertThat(response).hasRedirectedUrl(redirectedUrl);
}
@Test
void hasRedirectedUrlWithWrongValue() {
String redirectedUrl = "https://example.com/42";
MockHttpServletResponse response = new MockHttpServletResponse();
response.addHeader(HttpHeaders.LOCATION, redirectedUrl);
Assertions.assertThatExceptionOfType(AssertionError.class)
.isThrownBy(() -> assertThat(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");
}
@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 final class ResponseAssert extends AbstractMockHttpServletResponseAssert<ResponseAssert, MockHttpServletResponse> {
ResponseAssert(MockHttpServletResponse actual) {
super(null, actual, ResponseAssert.class);
}
@Override
protected MockHttpServletResponse getResponse() {
return this.actual;
}
}
}

View File

@@ -0,0 +1,88 @@
/*
* 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);
}
}