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:
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
* 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.time.ZoneId;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.List;
|
||||
|
||||
import org.assertj.core.api.AbstractMapAssert;
|
||||
import org.assertj.core.api.Assertions;
|
||||
|
||||
import org.springframework.http.HttpHeaders;
|
||||
|
||||
/**
|
||||
* AssertJ {@link org.assertj.core.api.Assert assertions} that can be applied to
|
||||
* {@link HttpHeaders}.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @since 6.2
|
||||
*/
|
||||
public class HttpHeadersAssert extends AbstractMapAssert<HttpHeadersAssert, HttpHeaders, String, List<String>> {
|
||||
|
||||
private static final ZoneId GMT = ZoneId.of("GMT");
|
||||
|
||||
|
||||
public HttpHeadersAssert(HttpHeaders actual) {
|
||||
super(actual, HttpHeadersAssert.class);
|
||||
as("HTTP headers");
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that the actual HTTP headers contain a header with the given
|
||||
* {@code name}.
|
||||
* @param name the name of an expected HTTP header
|
||||
* @see #containsKey
|
||||
*/
|
||||
public HttpHeadersAssert containsHeader(String name) {
|
||||
return containsKey(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that the actual HTTP headers contain the headers with the given
|
||||
* {@code names}.
|
||||
* @param names the names of expected HTTP headers
|
||||
* @see #containsKeys
|
||||
*/
|
||||
public HttpHeadersAssert containsHeaders(String... names) {
|
||||
return containsKeys(names);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that the actual HTTP headers do not contain a header with the
|
||||
* given {@code name}.
|
||||
* @param name the name of an HTTP header that should not be present
|
||||
* @see #doesNotContainKey
|
||||
*/
|
||||
public HttpHeadersAssert doesNotContainsHeader(String name) {
|
||||
return doesNotContainKey(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that the actual HTTP headers do not contain any of the headers
|
||||
* with the given {@code names}.
|
||||
* @param names the names of HTTP headers that should not be present
|
||||
* @see #doesNotContainKeys
|
||||
*/
|
||||
public HttpHeadersAssert doesNotContainsHeaders(String... names) {
|
||||
return doesNotContainKeys(names);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that the actual HTTP headers contain a header with the given
|
||||
* {@code name} and {@link String} {@code value}.
|
||||
* @param name the name of the cookie
|
||||
* @param value the expected value of the header
|
||||
*/
|
||||
public HttpHeadersAssert hasValue(String name, String value) {
|
||||
containsKey(name);
|
||||
Assertions.assertThat(this.actual.getFirst(name))
|
||||
.as("check primary value for HTTP header '%s'", name)
|
||||
.isEqualTo(value);
|
||||
return this.myself;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that the actual HTTP headers contain a header with the given
|
||||
* {@code name} and {@link Long} {@code value}.
|
||||
* @param name the name of the cookie
|
||||
* @param value the expected value of the header
|
||||
*/
|
||||
public HttpHeadersAssert hasValue(String name, long value) {
|
||||
containsKey(name);
|
||||
Assertions.assertThat(this.actual.getFirst(name))
|
||||
.as("check primary long value for HTTP header '%s'", name)
|
||||
.asLong().isEqualTo(value);
|
||||
return this.myself;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that the actual HTTP headers contain a header with the given
|
||||
* {@code name} and {@link Instant} {@code value}.
|
||||
* @param name the name of the cookie
|
||||
* @param value the expected value of the header
|
||||
*/
|
||||
public HttpHeadersAssert hasValue(String name, Instant value) {
|
||||
containsKey(name);
|
||||
Assertions.assertThat(this.actual.getFirstZonedDateTime(name))
|
||||
.as("check primary date value for HTTP header '%s'", name)
|
||||
.isCloseTo(ZonedDateTime.ofInstant(value, GMT), Assertions.within(999, ChronoUnit.MILLIS));
|
||||
return this.myself;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
* 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.assertj.core.api.AbstractObjectAssert;
|
||||
import org.assertj.core.api.Assertions;
|
||||
import org.assertj.core.error.BasicErrorMessageFactory;
|
||||
import org.assertj.core.internal.Failures;
|
||||
|
||||
import org.springframework.http.InvalidMediaTypeException;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* AssertJ {@link org.assertj.core.api.Assert assertions} that can be applied
|
||||
* to a {@link MediaType}.
|
||||
*
|
||||
* @author Brian Clozel
|
||||
* @author Stephane Nicoll
|
||||
* @since 6.2
|
||||
*/
|
||||
public class MediaTypeAssert extends AbstractObjectAssert<MediaTypeAssert, MediaType> {
|
||||
|
||||
public MediaTypeAssert(@Nullable MediaType mediaType) {
|
||||
super(mediaType, MediaTypeAssert.class);
|
||||
as("Media type");
|
||||
}
|
||||
|
||||
public MediaTypeAssert(@Nullable String actual) {
|
||||
this(StringUtils.hasText(actual) ? MediaType.parseMediaType(actual) : null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that the actual media type is equal to the given string
|
||||
* representation.
|
||||
* @param expected the expected media type
|
||||
*/
|
||||
public MediaTypeAssert isEqualTo(String expected) {
|
||||
return isEqualTo(parseMediaType(expected));
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that the actual media type is
|
||||
* {@linkplain MediaType#isCompatibleWith(MediaType) compatible} with the
|
||||
* given one. Example: <pre><code class='java'>
|
||||
* // Check that actual is compatible with "application/json"
|
||||
* assertThat(mediaType).isCompatibleWith(MediaType.APPLICATION_JSON);
|
||||
* </code></pre>
|
||||
* @param mediaType the media type with which to compare
|
||||
*/
|
||||
public MediaTypeAssert isCompatibleWith(MediaType mediaType) {
|
||||
Assertions.assertThat(this.actual)
|
||||
.withFailMessage("Expecting null to be compatible with '%s'", mediaType).isNotNull();
|
||||
Assertions.assertThat(mediaType)
|
||||
.withFailMessage("Expecting '%s' to be compatible with null", this.actual).isNotNull();
|
||||
Assertions.assertThat(this.actual.isCompatibleWith(mediaType))
|
||||
.as("check media type '%s' is compatible with '%s'", this.actual.toString(), mediaType.toString())
|
||||
.isTrue();
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that the actual media type is
|
||||
* {@linkplain MediaType#isCompatibleWith(MediaType) compatible} with the
|
||||
* given one. Example: <pre><code class='java'>
|
||||
* // Check that actual is compatible with "text/plain"
|
||||
* assertThat(mediaType).isCompatibleWith("text/plain");
|
||||
* </code></pre>
|
||||
* @param mediaType the media type with which to compare
|
||||
*/
|
||||
public MediaTypeAssert isCompatibleWith(String mediaType) {
|
||||
return isCompatibleWith(parseMediaType(mediaType));
|
||||
}
|
||||
|
||||
|
||||
private MediaType parseMediaType(String value) {
|
||||
try {
|
||||
return MediaType.parseMediaType(value);
|
||||
}
|
||||
catch (InvalidMediaTypeException ex) {
|
||||
throw Failures.instance().failure(this.info, new ShouldBeValidMediaType(value, ex.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
private static final class ShouldBeValidMediaType extends BasicErrorMessageFactory {
|
||||
|
||||
private ShouldBeValidMediaType(String mediaType, String errorMessage) {
|
||||
super("%nExpecting:%n %s%nTo be a valid media type but got:%n %s%n", mediaType, errorMessage);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
/**
|
||||
* Test support for HTTP concepts.
|
||||
*/
|
||||
@NonNullApi
|
||||
@NonNullFields
|
||||
package org.springframework.test.http;
|
||||
|
||||
import org.springframework.lang.NonNullApi;
|
||||
import org.springframework.lang.NonNullFields;
|
||||
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* 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.assertj.core.api.AbstractStringAssert;
|
||||
import org.assertj.core.api.Assertions;
|
||||
import org.assertj.core.error.BasicErrorMessageFactory;
|
||||
import org.assertj.core.internal.Failures;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.AntPathMatcher;
|
||||
import org.springframework.web.util.UriComponentsBuilder;
|
||||
|
||||
/**
|
||||
* AssertJ {@link org.assertj.core.api.Assert assertions} that can be applied
|
||||
* to a {@link String} representing a URI.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @since 6.2
|
||||
*/
|
||||
public class UriAssert extends AbstractStringAssert<UriAssert> {
|
||||
|
||||
private static final AntPathMatcher pathMatcher = new AntPathMatcher();
|
||||
|
||||
private final String displayName;
|
||||
|
||||
public UriAssert(@Nullable String actual, String displayName) {
|
||||
super(actual, UriAssert.class);
|
||||
this.displayName = displayName;
|
||||
as(displayName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that the actual URI is equal to the URI built using the given
|
||||
* {@code uriTemplate} and {@code uriVars}.
|
||||
* Example: <pre><code class='java'>
|
||||
* // Verify that uri is equal to "/orders/1/items/2"
|
||||
* assertThat(uri).isEqualToTemplate("/orders/{orderId}/items/{itemId}", 1, 2));
|
||||
* </code></pre>
|
||||
* @param uriTemplate the expected URI string, with a number of URI
|
||||
* template variables
|
||||
* @param uriVars the values to replace the URI template variables
|
||||
* @see UriComponentsBuilder#buildAndExpand(Object...)
|
||||
*/
|
||||
public UriAssert isEqualToTemplate(String uriTemplate, Object... uriVars) {
|
||||
String uri = buildUri(uriTemplate, uriVars);
|
||||
return isEqualTo(uri);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that the actual URI matches the given {@linkplain AntPathMatcher
|
||||
* Ant-style} {@code uriPattern}.
|
||||
* Example: <pre><code class='java'>
|
||||
* // Verify that pattern matches "/orders/1/items/2"
|
||||
* assertThat(uri).matchPattern("/orders/*"));
|
||||
* </code></pre>
|
||||
* @param uriPattern the pattern that is expected to match
|
||||
*/
|
||||
public UriAssert matchPattern(String uriPattern) {
|
||||
Assertions.assertThat(pathMatcher.isPattern(uriPattern))
|
||||
.withFailMessage("'%s' is not an Ant-style path pattern", uriPattern).isTrue();
|
||||
Assertions.assertThat(pathMatcher.match(uriPattern, this.actual))
|
||||
.withFailMessage("%s '%s' does not match the expected URI pattern '%s'",
|
||||
this.displayName, this.actual, uriPattern).isTrue();
|
||||
return this;
|
||||
}
|
||||
|
||||
private String buildUri(String uriTemplate, Object... uriVars) {
|
||||
try {
|
||||
return UriComponentsBuilder.fromUriString(uriTemplate)
|
||||
.buildAndExpand(uriVars).encode().toUriString();
|
||||
}
|
||||
catch (Exception ex) {
|
||||
throw Failures.instance().failure(this.info,
|
||||
new ShouldBeValidUriTemplate(uriTemplate, ex.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static final class ShouldBeValidUriTemplate extends BasicErrorMessageFactory {
|
||||
|
||||
private ShouldBeValidUriTemplate(String uriTemplate, String errorMessage) {
|
||||
super("%nExpecting:%n %s%nTo be a valid URI template but got:%n %s%n", uriTemplate, errorMessage);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
* 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.Enumeration;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpSession;
|
||||
import org.assertj.core.api.AbstractObjectAssert;
|
||||
import org.assertj.core.api.Assertions;
|
||||
import org.assertj.core.api.MapAssert;
|
||||
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.util.function.SingletonSupplier;
|
||||
import org.springframework.web.context.request.async.DeferredResult;
|
||||
|
||||
/**
|
||||
* Base AssertJ {@link org.assertj.core.api.Assert assertions} that can be
|
||||
* applied to a {@link HttpServletRequest}.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @since 6.2
|
||||
* @param <SELF> the type of assertions
|
||||
* @param <ACTUAL> the type of the object to assert
|
||||
*/
|
||||
public abstract class AbstractHttpServletRequestAssert<SELF extends AbstractHttpServletRequestAssert<SELF, ACTUAL>, ACTUAL extends HttpServletRequest>
|
||||
extends AbstractObjectAssert<SELF, ACTUAL> {
|
||||
|
||||
private final Supplier<MapAssert<String, Object>> attributesAssertProvider;
|
||||
|
||||
private final Supplier<MapAssert<String, Object>> sessionAttributesAssertProvider;
|
||||
|
||||
protected AbstractHttpServletRequestAssert(ACTUAL actual, Class<?> selfType) {
|
||||
super(actual, selfType);
|
||||
this.attributesAssertProvider = SingletonSupplier.of(() -> createAttributesAssert(actual));
|
||||
this.sessionAttributesAssertProvider = SingletonSupplier.of(() -> createSessionAttributesAssert(actual));
|
||||
}
|
||||
|
||||
private static MapAssert<String, Object> createAttributesAssert(HttpServletRequest request) {
|
||||
Map<String, Object> map = toMap(request.getAttributeNames(), request::getAttribute);
|
||||
return Assertions.assertThat(map).as("Request Attributes");
|
||||
}
|
||||
|
||||
private static MapAssert<String, Object> createSessionAttributesAssert(HttpServletRequest request) {
|
||||
HttpSession session = request.getSession();
|
||||
Assertions.assertThat(session).as("HTTP session").isNotNull();
|
||||
Map<String, Object> map = toMap(session.getAttributeNames(), session::getAttribute);
|
||||
return Assertions.assertThat(map).as("Session Attributes");
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a new {@linkplain MapAssert assertion} object that uses the request
|
||||
* attributes as the object to test, with values mapped by attribute name.
|
||||
* Examples: <pre><code class='java'>
|
||||
* // Check for the presence of a request attribute named "attributeName":
|
||||
* assertThat(request).attributes().containsKey("attributeName");
|
||||
* </code></pre>
|
||||
*/
|
||||
public MapAssert<String, Object> attributes() {
|
||||
return this.attributesAssertProvider.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a new {@linkplain MapAssert assertion} object that uses the session
|
||||
* attributes as the object to test, with values mapped by attribute name.
|
||||
* Examples: <pre><code class='java'>
|
||||
* // Check for the presence of a session attribute named "username":
|
||||
* assertThat(request).sessionAttributes().containsKey("username");
|
||||
* </code></pre>
|
||||
*/
|
||||
public MapAssert<String, Object> sessionAttributes() {
|
||||
return this.sessionAttributesAssertProvider.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that whether asynchronous processing started, usually as a result
|
||||
* of a controller method returning {@link Callable} or {@link DeferredResult}.
|
||||
* <p>The test will await the completion of a {@code Callable} so that
|
||||
* {@link MvcResultAssert#asyncResult()} can be used to assert the resulting
|
||||
* value.
|
||||
* <p>Neither a {@code Callable} nor a {@code DeferredResult} will complete
|
||||
* processing all the way since a {@link MockHttpServletRequest} does not
|
||||
* perform asynchronous dispatches.
|
||||
* @param started whether asynchronous processing should have started
|
||||
*/
|
||||
public SELF hasAsyncStarted(boolean started) {
|
||||
Assertions.assertThat(this.actual.isAsyncStarted())
|
||||
.withFailMessage("Async expected to %s started", (started ? "have" : "not have"))
|
||||
.isEqualTo(started);
|
||||
return this.myself;
|
||||
}
|
||||
|
||||
|
||||
private static Map<String, Object> toMap(Enumeration<String> keys, Function<String, Object> valueProvider) {
|
||||
Map<String, Object> map = new LinkedHashMap<>();
|
||||
while (keys.hasMoreElements()) {
|
||||
String key = keys.nextElement();
|
||||
map.put(key, valueProvider.apply(key));
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,167 @@
|
||||
/*
|
||||
* 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.ArrayList;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.assertj.core.api.AbstractIntegerAssert;
|
||||
import org.assertj.core.api.AbstractMapAssert;
|
||||
import org.assertj.core.api.AbstractObjectAssert;
|
||||
import org.assertj.core.api.Assertions;
|
||||
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.HttpStatus.Series;
|
||||
import org.springframework.test.http.HttpHeadersAssert;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.util.function.SingletonSupplier;
|
||||
|
||||
/**
|
||||
* Base AssertJ {@link org.assertj.core.api.Assert assertions} that can be
|
||||
* applied to any object that provides an {@link HttpServletResponse}. This
|
||||
* allows to provide direct access to response assertions while providing
|
||||
* access to a different top-level object.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @since 6.2
|
||||
* @param <R> the type of {@link HttpServletResponse}
|
||||
* @param <SELF> the type of assertions
|
||||
* @param <ACTUAL> the type of the object to assert
|
||||
*/
|
||||
public abstract class AbstractHttpServletResponseAssert<R extends HttpServletResponse, SELF extends AbstractHttpServletResponseAssert<R, SELF, ACTUAL>, ACTUAL>
|
||||
extends AbstractObjectAssert<SELF, ACTUAL> {
|
||||
|
||||
private final Supplier<AbstractIntegerAssert<?>> statusAssert;
|
||||
|
||||
private final Supplier<HttpHeadersAssert> headersAssertSupplier;
|
||||
|
||||
|
||||
protected AbstractHttpServletResponseAssert(ACTUAL actual, Class<?> selfType) {
|
||||
super(actual, selfType);
|
||||
this.statusAssert = SingletonSupplier.of(() -> Assertions.assertThat(getResponse().getStatus()).as("HTTP status code"));
|
||||
this.headersAssertSupplier = SingletonSupplier.of(() -> new HttpHeadersAssert(getHttpHeaders(getResponse())));
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide the response to use if it is available. Throw an
|
||||
* {@link AssertionError} if the request has failed to process and the
|
||||
* response is not available.
|
||||
* @return the response to use
|
||||
*/
|
||||
protected abstract R getResponse();
|
||||
|
||||
/**
|
||||
* Return a new {@linkplain HttpHeadersAssert assertion} object that uses
|
||||
* the {@link HttpHeaders} as the object to test. The return assertion
|
||||
* object provides all the regular {@linkplain AbstractMapAssert map
|
||||
* assertions}, with headers mapped by header name.
|
||||
* Examples: <pre><code class='java'>
|
||||
* // Check for the presence of the Accept header:
|
||||
* assertThat(response).headers().containsHeader(HttpHeaders.ACCEPT);
|
||||
* // Check for the absence of the Content-Length header:
|
||||
* assertThat(response).headers().doesNotContainsHeader(HttpHeaders.CONTENT_LENGTH);
|
||||
* </code></pre>
|
||||
*/
|
||||
public HttpHeadersAssert headers() {
|
||||
return this.headersAssertSupplier.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that the HTTP status is equal to the specified status code.
|
||||
* @param status the expected HTTP status code
|
||||
*/
|
||||
public SELF hasStatus(int status) {
|
||||
status().isEqualTo(status);
|
||||
return this.myself;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that the HTTP status is equal to the specified
|
||||
* {@linkplain HttpStatus status}.
|
||||
* @param status the expected HTTP status code
|
||||
*/
|
||||
public SELF hasStatus(HttpStatus status) {
|
||||
return hasStatus(status.value());
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that the HTTP status is equal to {@link HttpStatus#OK}.
|
||||
* @see #hasStatus(HttpStatus)
|
||||
*/
|
||||
public SELF hasStatusOk() {
|
||||
return hasStatus(HttpStatus.OK);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that the HTTP status code is in the 1xx range.
|
||||
* @see <a href="https://datatracker.ietf.org/doc/html/rfc2616#section-10.1">RFC 2616</a>
|
||||
*/
|
||||
public SELF hasStatus1xxInformational() {
|
||||
return hasStatusSeries(Series.INFORMATIONAL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that the HTTP status code is in the 2xx range.
|
||||
* @see <a href="https://datatracker.ietf.org/doc/html/rfc2616#section-10.2">RFC 2616</a>
|
||||
*/
|
||||
public SELF hasStatus2xxSuccessful() {
|
||||
return hasStatusSeries(Series.SUCCESSFUL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that the HTTP status code is in the 3xx range.
|
||||
* @see <a href="https://datatracker.ietf.org/doc/html/rfc2616#section-10.3">RFC 2616</a>
|
||||
*/
|
||||
public SELF hasStatus3xxRedirection() {
|
||||
return hasStatusSeries(Series.REDIRECTION);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that the HTTP status code is in the 4xx range.
|
||||
* @see <a href="https://datatracker.ietf.org/doc/html/rfc2616#section-10.4">RFC 2616</a>
|
||||
*/
|
||||
public SELF hasStatus4xxClientError() {
|
||||
return hasStatusSeries(Series.CLIENT_ERROR);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that the HTTP status code is in the 5xx range.
|
||||
* @see <a href="https://datatracker.ietf.org/doc/html/rfc2616#section-10.5">RFC 2616</a>
|
||||
*/
|
||||
public SELF hasStatus5xxServerError() {
|
||||
return hasStatusSeries(Series.SERVER_ERROR);
|
||||
}
|
||||
|
||||
private SELF hasStatusSeries(Series series) {
|
||||
Assertions.assertThat(Series.resolve(getResponse().getStatus())).as("HTTP status series").isEqualTo(series);
|
||||
return this.myself;
|
||||
}
|
||||
|
||||
private AbstractIntegerAssert<?> status() {
|
||||
return this.statusAssert.get();
|
||||
}
|
||||
|
||||
private static HttpHeaders getHttpHeaders(HttpServletResponse response) {
|
||||
MultiValueMap<String, String> headers = new LinkedMultiValueMap<>();
|
||||
response.getHeaderNames().forEach(name -> headers.put(name, new ArrayList<>(response.getHeaders(name))));
|
||||
return new HttpHeaders(headers);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* 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.springframework.mock.web.MockHttpServletRequest;
|
||||
|
||||
/**
|
||||
* AssertJ {@link org.assertj.core.api.Assert assertions} that can be applied to
|
||||
* {@link MockHttpServletRequest}.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @since 6.2
|
||||
* @param <SELF> the type of assertions
|
||||
*/
|
||||
public abstract class AbstractMockHttpServletRequestAssert<SELF extends AbstractMockHttpServletRequestAssert<SELF>>
|
||||
extends AbstractHttpServletRequestAssert<SELF, MockHttpServletRequest> {
|
||||
|
||||
protected AbstractMockHttpServletRequestAssert(MockHttpServletRequest request, Class<?> selfType) {
|
||||
super(request, selfType);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* 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 org.springframework.http.converter.GenericHttpMessageConverter;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
import org.springframework.test.web.UriAssert;
|
||||
|
||||
/**
|
||||
* Extension of {@link AbstractHttpServletResponseAssert} for
|
||||
* {@link MockHttpServletResponse}.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @since 6.2
|
||||
* @param <SELF> the type of assertions
|
||||
* @param <ACTUAL> the type of the object to assert
|
||||
*/
|
||||
public abstract class AbstractMockHttpServletResponseAssert<SELF extends AbstractMockHttpServletResponseAssert<SELF, ACTUAL>, ACTUAL>
|
||||
extends AbstractHttpServletResponseAssert<MockHttpServletResponse, SELF, ACTUAL> {
|
||||
|
||||
@Nullable
|
||||
private final GenericHttpMessageConverter<Object> jsonMessageConverter;
|
||||
|
||||
protected AbstractMockHttpServletResponseAssert(
|
||||
@Nullable GenericHttpMessageConverter<Object> jsonMessageConverter, ACTUAL actual, Class<?> selfType) {
|
||||
|
||||
super(actual, selfType);
|
||||
this.jsonMessageConverter = jsonMessageConverter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a new {@linkplain ResponseBodyAssert assertion} object that uses
|
||||
* the response body as the object to test. The return assertion object
|
||||
* provides access to the raw byte array, a String value decoded using the
|
||||
* response's character encoding, and dedicated json testing support.
|
||||
* 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");
|
||||
* </code></pre>
|
||||
*/
|
||||
public ResponseBodyAssert body() {
|
||||
return new ResponseBodyAssert(getResponse().getContentAsByteArray(),
|
||||
Charset.forName(getResponse().getCharacterEncoding()), this.jsonMessageConverter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a new {@linkplain UriAssert assertion} object that uses the
|
||||
* forwarded URL as the object to test. If a simple equality check is
|
||||
* required consider using {@link #hasForwardedUrl(String)} instead.
|
||||
* Example: <pre><code class='java'>
|
||||
* // Check that the forwarded URL starts with "/orders/":
|
||||
* assertThat(response).forwardedUrl().matchPattern("/orders/*);
|
||||
* </code></pre>
|
||||
*/
|
||||
public UriAssert forwardedUrl() {
|
||||
return new UriAssert(getResponse().getForwardedUrl(), "Forwarded URL");
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a new {@linkplain UriAssert assertion} object that uses the
|
||||
* redirected URL as the object to test. If a simple equality check is
|
||||
* required consider using {@link #hasRedirectedUrl(String)} instead.
|
||||
* Example: <pre><code class='java'>
|
||||
* // Check that the redirected URL starts with "/orders/":
|
||||
* assertThat(response).redirectedUrl().matchPattern("/orders/*);
|
||||
* </code></pre>
|
||||
*/
|
||||
public UriAssert redirectedUrl() {
|
||||
return new UriAssert(getResponse().getRedirectedUrl(), "Redirected URL");
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that the forwarded URL is equal to the given value.
|
||||
* @param forwardedUrl the expected forwarded URL (can be null)
|
||||
*/
|
||||
public SELF hasForwardedUrl(@Nullable String forwardedUrl) {
|
||||
forwardedUrl().isEqualTo(forwardedUrl);
|
||||
return this.myself;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that the redirected URL is equal to the given value.
|
||||
* @param redirectedUrl the expected redirected URL (can be null)
|
||||
*/
|
||||
public SELF hasRedirectedUrl(@Nullable String redirectedUrl) {
|
||||
redirectedUrl().isEqualTo(redirectedUrl);
|
||||
return this.myself;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
* 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.JsonContentAssert;
|
||||
import org.springframework.test.json.JsonPathAssert;
|
||||
|
||||
/**
|
||||
* 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 JsonPathAssert assertion} object that provides
|
||||
* {@linkplain com.jayway.jsonpath.JsonPath JSON path} assertions on the
|
||||
* response body.
|
||||
*/
|
||||
public JsonPathAssert jsonPath() {
|
||||
return new JsonPathAssert(getJson(), this.jsonMessageConverter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a new {@linkplain JsonContentAssert assertion} object that
|
||||
* provides {@linkplain org.skyscreamer.jsonassert.JSONCompareMode JSON
|
||||
* assert} comparison to expected json input that can be loaded from the
|
||||
* classpath. Only absolute locations are supported, consider using
|
||||
* {@link #json(Class)} to load json documents relative to a given class.
|
||||
* 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 JsonContentAssert json() {
|
||||
return json(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a new {@linkplain JsonContentAssert assertion} object that
|
||||
* provides {@linkplain org.skyscreamer.jsonassert.JSONCompareMode JSON
|
||||
* assert} comparison to expected json input that can be loaded from the
|
||||
* classpath. Documents can be absolute using a leading slash, or relative
|
||||
* to the given {@code resourceLoadClass}.
|
||||
* Example: <pre><code class='java'>
|
||||
* // Check that the response is strictly equal to the content of
|
||||
* // the specified file:
|
||||
* 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 JsonContentAssert json(@Nullable Class<?> resourceLoadClass) {
|
||||
return new JsonContentAssert(getJson(), resourceLoadClass, this.characterEncoding);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that the response body is equal to the given {@link String}.
|
||||
* <p>Convert 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 {@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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
/**
|
||||
* AssertJ support for MockMvc.
|
||||
*/
|
||||
@NonNullApi
|
||||
@NonNullFields
|
||||
package org.springframework.test.web.servlet.assertj;
|
||||
|
||||
import org.springframework.lang.NonNullApi;
|
||||
import org.springframework.lang.NonNullFields;
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user