Polish AssertJ support for MockMvc

See gh-21178
This commit is contained in:
Sam Brannen 2024-03-15 17:15:32 +01:00
parent 4a74e1fc2d
commit cf31d088e2
31 changed files with 276 additions and 258 deletions

View File

@ -36,14 +36,15 @@ import org.springframework.util.StringUtils;
*/
public class MediaTypeAssert extends AbstractObjectAssert<MediaTypeAssert, MediaType> {
public MediaTypeAssert(@Nullable String actual) {
this(StringUtils.hasText(actual) ? MediaType.parseMediaType(actual) : null);
}
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
@ -57,7 +58,8 @@ public class MediaTypeAssert extends AbstractObjectAssert<MediaTypeAssert, Media
/**
* Verify that the actual media type is
* {@linkplain MediaType#isCompatibleWith(MediaType) compatible} with the
* given one. Example: <pre><code class='java'>
* given one.
* <p>Example: <pre><code class='java'>
* // Check that actual is compatible with "application/json"
* assertThat(mediaType).isCompatibleWith(MediaType.APPLICATION_JSON);
* </code></pre>
@ -77,7 +79,8 @@ public class MediaTypeAssert extends AbstractObjectAssert<MediaTypeAssert, Media
/**
* Verify that the actual media type is
* {@linkplain MediaType#isCompatibleWith(MediaType) compatible} with the
* given one. Example: <pre><code class='java'>
* given one.
* <p>Example: <pre><code class='java'>
* // Check that actual is compatible with "text/plain"
* assertThat(mediaType).isCompatibleWith("text/plain");
* </code></pre>

View File

@ -16,7 +16,6 @@
package org.springframework.test.json;
import java.lang.reflect.Array;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;
@ -43,8 +42,9 @@ import org.springframework.util.StringUtils;
/**
* Base AssertJ {@link org.assertj.core.api.Assert assertions} that can be
* applied to a JSON value. In JSON, values must be one of the following data
* types:
* applied to a JSON value.
*
* <p>In JSON, values must be one of the following data types:
* <ul>
* <li>a {@linkplain #asString() string}</li>
* <li>a {@linkplain #asNumber() number}</li>
@ -53,7 +53,7 @@ import org.springframework.util.StringUtils;
* <li>an {@linkplain #asMap() object} (JSON object)</li>
* <li>{@linkplain #isNull() null}</li>
* </ul>
* This base class offers direct access for each of those types as well as a
* This base class offers direct access for each of those types as well as
* conversion methods based on an optional {@link GenericHttpMessageConverter}.
*
* @author Stephane Nicoll
@ -71,12 +71,14 @@ public abstract class AbstractJsonValueAssert<SELF extends AbstractJsonValueAsse
protected AbstractJsonValueAssert(@Nullable Object actual, Class<?> selfType,
@Nullable GenericHttpMessageConverter<Object> httpMessageConverter) {
super(actual, selfType);
this.httpMessageConverter = httpMessageConverter;
}
/**
* Verify that the actual value is a non-{@code null} {@link String}
* Verify that the actual value is a non-{@code null} {@link String},
* and return a new {@linkplain AbstractStringAssert assertion} object that
* provides dedicated {@code String} assertions for it.
*/
@ -87,7 +89,7 @@ public abstract class AbstractJsonValueAssert<SELF extends AbstractJsonValueAsse
/**
* Verify that the actual value is a non-{@code null} {@link Number},
* usually an {@link Integer} or {@link Double} and return a new
* usually an {@link Integer} or {@link Double}, and return a new
* {@linkplain AbstractObjectAssert assertion} object for it.
*/
public AbstractObjectAssert<?, Number> asNumber() {
@ -95,7 +97,7 @@ public abstract class AbstractJsonValueAssert<SELF extends AbstractJsonValueAsse
}
/**
* Verify that the actual value is a non-{@code null} {@link Boolean}
* Verify that the actual value is a non-{@code null} {@link Boolean},
* and return a new {@linkplain AbstractBooleanAssert assertion} object
* that provides dedicated {@code Boolean} assertions for it.
*/
@ -104,9 +106,9 @@ public abstract class AbstractJsonValueAssert<SELF extends AbstractJsonValueAsse
}
/**
* Verify that the actual value is a non-{@code null} {@link Array}
* and return a new {@linkplain ObjectArrayAssert assertion} object
* that provides dedicated {@code Array} assertions for it.
* Verify that the actual value is a non-{@code null} array, and return a
* new {@linkplain ObjectArrayAssert assertion} object that provides dedicated
* array assertions for it.
*/
public ObjectArrayAssert<Object> asArray() {
List<?> list = castTo(List.class, "an array");
@ -115,11 +117,12 @@ public abstract class AbstractJsonValueAssert<SELF extends AbstractJsonValueAsse
}
/**
* Verify that the actual value is a non-{@code null} JSON object and
* Verify that the actual value is a non-{@code null} JSON object, and
* return a new {@linkplain AbstractMapAssert assertion} object that
* provides dedicated assertions on individual elements of the
* object. The returned map assertion object uses the attribute name as the
* key, and the value can itself be any of the valid JSON values.
* object.
* <p>The returned map assertion object uses attribute names as the keys,
* and the values can be any of the valid JSON values.
*/
@SuppressWarnings("unchecked")
public AbstractMapAssert<?, Map<String, Object>, String, Object> asMap() {
@ -138,7 +141,7 @@ public abstract class AbstractJsonValueAssert<SELF extends AbstractJsonValueAsse
/**
* Verify that the actual value can be converted to an instance of the
* given {@code target} and produce a new {@linkplain AbstractObjectAssert
* given {@code target}, and produce a new {@linkplain AbstractObjectAssert
* assertion} object narrowed to that type.
* @param target the {@linkplain Class type} to convert the actual value to
*/
@ -150,7 +153,7 @@ public abstract class AbstractJsonValueAssert<SELF extends AbstractJsonValueAsse
/**
* Verify that the actual value can be converted to an instance of the
* given {@code target} and produce a new {@linkplain AbstractObjectAssert
* given {@code target}, and produce a new {@linkplain AbstractObjectAssert
* assertion} object narrowed to that type.
* @param target the {@linkplain ParameterizedTypeReference parameterized
* type} to convert the actual value to
@ -162,9 +165,10 @@ public abstract class AbstractJsonValueAssert<SELF extends AbstractJsonValueAsse
}
/**
* Verify that the actual value is empty, that is a {@code null} scalar
* value or an empty list or map. Can also be used when the path is using a
* filter operator to validate that it dit not match.
* Verify that the actual value is empty: either a {@code null} scalar value
* or an empty list or map.
* <p>Can also be used when the path uses a filter operator to validate that
* it did not match.
*/
public SELF isEmpty() {
if (!ObjectUtils.isEmpty(this.actual)) {
@ -174,10 +178,10 @@ public abstract class AbstractJsonValueAssert<SELF extends AbstractJsonValueAsse
}
/**
* Verify that the actual value is not empty, that is a non-{@code null}
* scalar value or a non-empty list or map. Can also be used when the path is
* using a filter operator to validate that it dit match at least one
* element.
* Verify that the actual value is not empty: either a non-{@code null}
* scalar value or a non-empty list or map.
* <p>Can also be used when the path uses a filter operator to validate that
* it did match at least one element.
*/
public SELF isNotEmpty() {
if (ObjectUtils.isEmpty(this.actual)) {
@ -225,6 +229,7 @@ public abstract class AbstractJsonValueAssert<SELF extends AbstractJsonValueAsse
return ObjectUtils.nullSafeToString(StringUtils.quoteIfString(this.actual));
}
private static final class ValueProcessingFailed extends BasicErrorMessageFactory {
private ValueProcessingFailed(String prefix, String actualToString, String errorMessage) {

View File

@ -22,9 +22,8 @@ import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
* JSON content usually created from a JSON tester. Generally used only to
* {@link AssertProvider provide} {@link JsonContentAssert} to AssertJ
* {@code assertThat} calls.
* JSON content which is generally used to {@link AssertProvider provide}
* {@link JsonContentAssert} to AssertJ {@code assertThat} calls.
*
* @author Phillip Webb
* @author Diego Berrueta
@ -37,8 +36,9 @@ public final class JsonContent implements AssertProvider<JsonContentAssert> {
@Nullable
private final Class<?> resourceLoadClass;
/**
* Create a new {@link JsonContent} instance.
* Create a new {@code JsonContent} instance.
* @param json the actual JSON content
* @param resourceLoadClass the source class used to load resources
*/
@ -48,6 +48,7 @@ public final class JsonContent implements AssertProvider<JsonContentAssert> {
this.resourceLoadClass = resourceLoadClass;
}
/**
* Use AssertJ's {@link org.assertj.core.api.Assertions#assertThat assertThat}
* instead.

View File

@ -37,8 +37,8 @@ import org.springframework.util.function.ThrowingBiFunction;
/**
* AssertJ {@link org.assertj.core.api.Assert assertions} that can be applied
* to a {@link CharSequence} representation of a json document, mostly to
* compare the json document against a target, using {@linkplain JSONCompare
* to a {@link CharSequence} representation of a JSON document, mostly to
* compare the JSON document against a target, using {@linkplain JSONCompare
* JSON Assert}.
*
* @author Phillip Webb
@ -57,7 +57,7 @@ public class JsonContentAssert extends AbstractAssert<JsonContentAssert, CharSeq
* relative to the given {@code resourceLoadClass}, using the given
* {@code charset}.
* @param json the actual JSON content
* @param resourceLoadClass the source class used to load resources
* @param resourceLoadClass the class used to load resources
* @param charset the charset of the JSON resources
*/
public JsonContentAssert(@Nullable CharSequence json, @Nullable Class<?> resourceLoadClass,
@ -71,7 +71,7 @@ public class JsonContentAssert extends AbstractAssert<JsonContentAssert, CharSeq
* Create a new {@link JsonContentAssert} instance that will load resources
* relative to the given {@code resourceLoadClass}, using {@code UTF-8}.
* @param json the actual JSON content
* @param resourceLoadClass the source class used to load resources
* @param resourceLoadClass the class used to load resources
*/
public JsonContentAssert(@Nullable CharSequence json, @Nullable Class<?> resourceLoadClass) {
this(json, resourceLoadClass, null);
@ -343,7 +343,6 @@ public class JsonContentAssert extends AbstractAssert<JsonContentAssert, CharSeq
private JSONCompareResult compareForNull(@Nullable CharSequence expectedJson) {
JSONCompareResult result = new JSONCompareResult();
result.passed();
if (expectedJson != null) {
result.fail("Expected null JSON");
}
@ -352,14 +351,14 @@ public class JsonContentAssert extends AbstractAssert<JsonContentAssert, CharSeq
private JsonContentAssert assertNotFailed(JSONCompareResult result) {
if (result.failed()) {
failWithMessage("JSON Comparison failure: %s", result.getMessage());
failWithMessage("JSON comparison failure: %s", result.getMessage());
}
return this;
}
private JsonContentAssert assertNotPassed(JSONCompareResult result) {
if (result.passed()) {
failWithMessage("JSON Comparison failure: %s", result.getMessage());
failWithMessage("JSON comparison failure: %s", result.getMessage());
}
return this;
}

View File

@ -42,20 +42,23 @@ class JsonLoader {
private final Charset charset;
JsonLoader(@Nullable Class<?> resourceLoadClass, @Nullable Charset charset) {
this.resourceLoadClass = resourceLoadClass;
this.charset = (charset != null ? charset : StandardCharsets.UTF_8);
}
@Nullable
String getJson(@Nullable CharSequence source) {
if (source == null) {
return null;
}
if (source.toString().endsWith(".json")) {
return getJson(new ClassPathResource(source.toString(), this.resourceLoadClass));
String string = source.toString();
if (string.endsWith(".json")) {
return getJson(new ClassPathResource(string, this.resourceLoadClass));
}
return source.toString();
return string;
}
String getJson(Resource source) {

View File

@ -31,7 +31,7 @@ import org.springframework.util.Assert;
/**
* AssertJ {@link org.assertj.core.api.Assert assertions} that can be applied
* to a {@link CharSequence} representation of a json document using
* to a {@link CharSequence} representation of a JSON document using
* {@linkplain JsonPath JSON path}.
*
* @author Stephane Nicoll
@ -41,17 +41,21 @@ public class JsonPathAssert extends AbstractAssert<JsonPathAssert, CharSequence>
private static final Failures failures = Failures.instance();
@Nullable
private final GenericHttpMessageConverter<Object> jsonMessageConverter;
public JsonPathAssert(CharSequence json,
@Nullable GenericHttpMessageConverter<Object> jsonMessageConverter) {
super(json, JsonPathAssert.class);
this.jsonMessageConverter = jsonMessageConverter;
}
/**
* Verify that the given JSON {@code path} is present and extract the JSON
* Verify that the given JSON {@code path} is present, and extract the JSON
* value for further {@linkplain JsonPathValueAssert assertions}.
* @param path the {@link JsonPath} expression
* @see #hasPathSatisfying(String, Consumer)
@ -158,8 +162,9 @@ public class JsonPathAssert extends AbstractAssert<JsonPathAssert, CharSequence>
static final class JsonPathNotExpected extends BasicErrorMessageFactory {
private JsonPathNotExpected(String actual, String path) {
super("%nExpecting:%n %s%nTo not match JSON path:%n %s%n", actual, path);
super("%nExpecting:%n %s%nNot to match JSON path:%n %s%n", actual, path);
}
}
}
}

View File

@ -29,14 +29,14 @@ import org.springframework.lang.Nullable;
* @author Stephane Nicoll
* @since 6.2
*/
public class JsonPathValueAssert
extends AbstractJsonValueAssert<JsonPathValueAssert> {
public class JsonPathValueAssert extends AbstractJsonValueAssert<JsonPathValueAssert> {
private final String expression;
JsonPathValueAssert(@Nullable Object actual, String expression,
@Nullable GenericHttpMessageConverter<Object> httpMessageConverter) {
super(actual, JsonPathValueAssert.class, httpMessageConverter);
this.expression = expression;
}
@ -45,4 +45,5 @@ public class JsonPathValueAssert
protected String getExpectedErrorMessagePrefix() {
return "Expected value at JSON path \"%s\":".formatted(this.expression);
}
}

View File

@ -44,6 +44,7 @@ public abstract class AbstractBindingResultAssert<SELF extends AbstractBindingRe
private final String name;
protected AbstractBindingResultAssert(String name, BindingResult bindingResult, Class<?> selfType) {
super(bindingResult, selfType);
this.name = name;
@ -51,7 +52,7 @@ public abstract class AbstractBindingResultAssert<SELF extends AbstractBindingRe
}
/**
* Verify that the total number of errors is equal to the given one.
* Verify that the total number of errors is equal to the expected value.
* @param expected the expected number of errors
*/
public SELF hasErrorsCount(int expected) {
@ -73,7 +74,7 @@ public abstract class AbstractBindingResultAssert<SELF extends AbstractBindingRe
/**
* Verify that the actual binding result contains <em>only</em> fields in
* error with the given {@code fieldNames}, and nothing else.
* @param fieldNames the exhaustive list of field name that should be in error
* @param fieldNames the exhaustive list of field names that should be in error
*/
public SELF hasOnlyFieldErrors(String... fieldNames) {
assertThat(fieldErrorNames()).containsOnly(fieldNames);

View File

@ -70,7 +70,7 @@ public class UriAssert extends AbstractStringAssert<UriAssert> {
* </code></pre>
* @param uriPattern the pattern that is expected to match
*/
public UriAssert matchPattern(String uriPattern) {
public UriAssert matchesPattern(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))

View File

@ -35,7 +35,7 @@ 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}.
* applied to an {@link HttpServletRequest}.
*
* @author Stephane Nicoll
* @since 6.2
@ -70,7 +70,7 @@ public abstract class AbstractHttpServletRequestAssert<SELF extends AbstractHttp
/**
* 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'>
* <p>Example: <pre><code class='java'>
* // Check for the presence of a request attribute named "attributeName":
* assertThat(request).attributes().containsKey("attributeName");
* </code></pre>
@ -82,7 +82,7 @@ public abstract class AbstractHttpServletRequestAssert<SELF extends AbstractHttp
/**
* 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'>
* <p>Example: <pre><code class='java'>
* // Check for the presence of a session attribute named "username":
* assertThat(request).sessionAttributes().containsKey("username");
* </code></pre>
@ -92,8 +92,8 @@ public abstract class AbstractHttpServletRequestAssert<SELF extends AbstractHttp
}
/**
* Verify that whether asynchronous processing started, usually as a result
* of a controller method returning {@link Callable} or {@link DeferredResult}.
* Verify whether asynchronous processing has started, usually as a result
* of a controller method returning a {@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.
@ -104,7 +104,7 @@ public abstract class AbstractHttpServletRequestAssert<SELF extends AbstractHttp
*/
public SELF hasAsyncStarted(boolean started) {
Assertions.assertThat(this.actual.isAsyncStarted())
.withFailMessage("Async expected to %s started", (started ? "have" : "not have"))
.withFailMessage("Async expected %sto have started", (started ? "" : "not "))
.isEqualTo(started);
return this.myself;
}

View File

@ -36,8 +36,8 @@ 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.
* provides direct access to response assertions while also providing access to
* a different top-level object.
*
* @author Stephane Nicoll
* @since 6.2
@ -60,21 +60,22 @@ public abstract class AbstractHttpServletResponseAssert<R extends HttpServletRes
}
/**
* 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.
* Provide the response to use if it is available.
* <p>Throws 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
* {@link HttpHeaders} as the object to test. The returned 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>

View File

@ -33,6 +33,4 @@ public abstract class AbstractMockHttpServletRequestAssert<SELF extends Abstract
super(request, selfType);
}
}

View File

@ -47,12 +47,13 @@ public abstract class AbstractMockHttpServletResponseAssert<SELF extends Abstrac
/**
* Return a new {@linkplain ResponseBodyAssert assertion} object that uses
* the response body as the object to test. The return assertion object
* the response body as the object to test. The returned 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'>
* response's character encoding, and dedicated JSON testing support.
* <p>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>
@ -65,8 +66,8 @@ public abstract class AbstractMockHttpServletResponseAssert<SELF extends Abstrac
/**
* 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'>
* required, consider using {@link #hasForwardedUrl(String)} instead.
* <p>Example: <pre><code class='java'>
* // Check that the forwarded URL starts with "/orders/":
* assertThat(response).forwardedUrl().matchPattern("/orders/*);
* </code></pre>
@ -78,8 +79,8 @@ public abstract class AbstractMockHttpServletResponseAssert<SELF extends Abstrac
/**
* 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'>
* required, consider using {@link #hasRedirectedUrl(String)} instead.
* <p>Example: <pre><code class='java'>
* // Check that the redirected URL starts with "/orders/":
* assertThat(response).redirectedUrl().matchPattern("/orders/*);
* </code></pre>

View File

@ -38,7 +38,7 @@ import org.springframework.util.Assert;
import org.springframework.web.context.WebApplicationContext;
/**
* {@link MockMvc} variant that tests Spring MVC exchanges and provide fluent
* {@link MockMvc} variant that tests Spring MVC exchanges and provides fluent
* assertions using {@link org.assertj.core.api.Assertions AssertJ}.
*
* <p>A main difference with {@link MockMvc} is that an unresolved exception
@ -47,7 +47,7 @@ import org.springframework.web.context.WebApplicationContext;
* exception}.
*
* <p>{@link AssertableMockMvc} can be configured with a list of
* {@linkplain HttpMessageConverter HttpMessageConverters} to allow response
* {@linkplain HttpMessageConverter message converters} to allow the response
* body to be deserialized, rather than asserting on the raw values.
*
* @author Stephane Nicoll
@ -71,8 +71,8 @@ public final class AssertableMockMvc {
}
/**
* Create a new {@link AssertableMockMvc} instance that delegates to the
* given {@link MockMvc}.
* Create a {@link AssertableMockMvc} instance that delegates to the given
* {@link MockMvc} instance.
* @param mockMvc the MockMvc instance to delegate calls to
*/
public static AssertableMockMvc create(MockMvc mockMvc) {
@ -80,7 +80,7 @@ public final class AssertableMockMvc {
}
/**
* Create a {@link AssertableMockMvc} instance using the given, fully
* Create an {@link AssertableMockMvc} instance using the given, fully
* initialized (i.e., <em>refreshed</em>) {@link WebApplicationContext}. The
* given {@code customizations} are applied to the {@link DefaultMockMvcBuilder}
* that ultimately creates the underlying {@link MockMvc} instance.
@ -88,7 +88,7 @@ public final class AssertableMockMvc {
* is required, use {@link #from(WebApplicationContext)}.
* @param applicationContext the application context to detect the Spring
* MVC infrastructure and application controllers from
* @param customizations the function that creates a {@link MockMvc}
* @param customizations a function that creates a {@link MockMvc}
* instance based on a {@link DefaultMockMvcBuilder}.
* @see MockMvcBuilders#webAppContextSetup(WebApplicationContext)
*/
@ -101,10 +101,10 @@ public final class AssertableMockMvc {
}
/**
* Shortcut to create a {@link AssertableMockMvc} instance using the given,
* Shortcut to create an {@link AssertableMockMvc} instance using the given,
* fully initialized (i.e., <em>refreshed</em>) {@link WebApplicationContext}.
* <p>Consider using {@link #from(WebApplicationContext, Function)} if
* further customizations of the underlying {@link MockMvc} instance is
* further customization of the underlying {@link MockMvc} instance is
* required.
* @param applicationContext the application context to detect the Spring
* MVC infrastructure and application controllers from
@ -115,17 +115,18 @@ public final class AssertableMockMvc {
}
/**
* Create a {@link AssertableMockMvc} instance by registering one or more
* Create an {@link AssertableMockMvc} instance by registering one or more
* {@code @Controller} instances and configuring Spring MVC infrastructure
* programmatically.
* <p>This allows full control over the instantiation and initialization of
* controllers and their dependencies, similar to plain unit tests while
* also making it possible to test one controller at a time.
* @param controllers one or more {@code @Controller} instances to test
* (specified {@code Class} will be turned into instance)
* @param customizations the function that creates a {@link MockMvc}
* instance based on a {@link StandaloneMockMvcBuilder}, typically to
* configure the Spring MVC infrastructure
* @param controllers one or more {@code @Controller} instances or
* {@code @Controller} types to test; a type ({@code Class}) will be turned
* into an instance
* @param customizations a function that creates a {@link MockMvc} instance
* based on a {@link StandaloneMockMvcBuilder}, typically to configure the
* Spring MVC infrastructure
* @see MockMvcBuilders#standaloneSetup(Object...)
*/
public static AssertableMockMvc of(Collection<?> controllers,
@ -136,15 +137,16 @@ public final class AssertableMockMvc {
}
/**
* Shortcut to create a {@link AssertableMockMvc} instance by registering
* Shortcut to create an {@link AssertableMockMvc} instance by registering
* one or more {@code @Controller} instances.
* <p>The minimum infrastructure required by the
* {@link org.springframework.web.servlet.DispatcherServlet DispatcherServlet}
* to serve requests with annotated controllers is created. Consider using
* {@link #of(Collection, Function)} if additional configuration of the MVC
* infrastructure is required.
* @param controllers one or more {@code @Controller} instances to test
* (specified {@code Class} will be turned into instance)
* @param controllers one or more {@code @Controller} instances or
* {@code @Controller} types to test; a type ({@code Class}) will be turned
* into an instance
* @see MockMvcBuilders#standaloneSetup(Object...)
*/
public static AssertableMockMvc of(Object... controllers) {
@ -153,9 +155,10 @@ public final class AssertableMockMvc {
/**
* Return a new {@link AssertableMockMvc} instance using the specified
* {@link HttpMessageConverter}. If none are specified, only basic assertions
* on the response body can be performed. Consider registering a suitable
* JSON converter for asserting data structure.
* {@linkplain HttpMessageConverter message converters}.
* <p>If none are specified, only basic assertions on the response body can
* be performed. Consider registering a suitable JSON converter for asserting
* against JSON data structures.
* @param httpMessageConverters the message converters to use
* @return a new instance using the specified converters
*/
@ -169,7 +172,7 @@ public final class AssertableMockMvc {
* <p>Use static methods of {@link MockMvcRequestBuilders} to prepare the
* request, wrapping the invocation in {@code assertThat}. The following
* asserts that a {@linkplain MockMvcRequestBuilders#get(URI) GET} request
* against "/greet" has an HTTP status code 200 (OK), and a simple body:
* against "/greet" has an HTTP status code 200 (OK) and a simple body:
* <pre><code class='java'>assertThat(mvc.perform(get("/greet")))
* .hasStatusOk()
* .body().asString().isEqualTo("Hello");
@ -177,7 +180,7 @@ public final class AssertableMockMvc {
* <p>Contrary to {@link MockMvc#perform(RequestBuilder)}, this does not
* throw an exception if the request fails with an unresolved exception.
* Rather, the result provides the exception, if any. Assuming that a
* {@linkplain MockMvcRequestBuilders#post(URI) POST} request against
* {@link MockMvcRequestBuilders#post(URI) POST} request against
* {@code /boom} throws an {@code IllegalStateException}, the following
* asserts that the invocation has indeed failed with the expected error
* message:
@ -185,7 +188,6 @@ public final class AssertableMockMvc {
* .unresolvedException().isInstanceOf(IllegalStateException.class)
* .hasMessage("Expected");
* </code></pre>
* <p>
* @param requestBuilder used to prepare the request to execute;
* see static factory methods in
* {@link org.springframework.test.web.servlet.request.MockMvcRequestBuilders}

View File

@ -24,13 +24,13 @@ import org.springframework.test.web.servlet.MvcResult;
/**
* A {@link MvcResult} that additionally supports AssertJ style assertions.
*
* <p>Can be in two distinct states:
* <p>Can be in one of two distinct states:
* <ol>
* <li>The request processed successfully, and {@link #getUnresolvedException()}
* is therefore {@code null}.</li>
* <li>The request failed unexpectedly with {@link #getUnresolvedException()}
* providing more information about the error. Any attempt to access a
* member of the result fails with an exception.</li>
* providing more information about the error. Any attempt to access a member of
* the result fails with an exception.</li>
* </ol>
*
* @author Stephane Nicoll

View File

@ -58,8 +58,7 @@ public class CookieMapAssert extends AbstractMapAssert<CookieMapAssert, Map<Stri
}
/**
* Verify that the actual cookies contain the cookies with the given
* {@code names}.
* Verify that the actual cookies contain cookies with the given {@code names}.
* @param names the names of expected cookies
* @see #containsKeys
*/
@ -68,8 +67,8 @@ public class CookieMapAssert extends AbstractMapAssert<CookieMapAssert, Map<Stri
}
/**
* Verify that the actual cookies do not contain a cookie with the
* given {@code name}.
* Verify that the actual cookies do not contain a cookie with the given
* {@code name}.
* @param name the name of a cookie that should not be present
* @see #doesNotContainKey
*/
@ -78,8 +77,8 @@ public class CookieMapAssert extends AbstractMapAssert<CookieMapAssert, Map<Stri
}
/**
* Verify that the actual cookies do not contain any of the cookies with
* the given {@code names}.
* Verify that the actual cookies do not contain any cookies with the given
* {@code names}.
* @param names the names of cookies that should not be present
* @see #doesNotContainKeys
*/
@ -88,9 +87,8 @@ public class CookieMapAssert extends AbstractMapAssert<CookieMapAssert, Map<Stri
}
/**
* Verify that the actual cookies contain a cookie with the given
* {@code name} that satisfy given {@code cookieRequirements}.
* the specified names.
* Verify that the actual cookies contain a cookie with the given {@code name}
* that satisfies the given {@code cookieRequirements}.
* @param name the name of an expected cookie
* @param cookieRequirements the requirements for the cookie
*/
@ -99,9 +97,8 @@ public class CookieMapAssert extends AbstractMapAssert<CookieMapAssert, Map<Stri
}
/**
* Verify that the actual cookies contain a cookie with the given
* {@code name} whose {@linkplain Cookie#getValue() value} is equal to the
* given one.
* Verify that the actual cookies contain a cookie with the given {@code name}
* whose {@linkplain Cookie#getValue() value} is equal to the expected value.
* @param name the name of the cookie
* @param expected the expected value of the cookie
*/
@ -111,9 +108,8 @@ public class CookieMapAssert extends AbstractMapAssert<CookieMapAssert, Map<Stri
}
/**
* Verify that the actual cookies contain a cookie with the given
* {@code name} whose {@linkplain Cookie#getMaxAge() max age} is equal to
* the given one.
* Verify that the actual cookies contain a cookie with the given {@code name}
* whose {@linkplain Cookie#getMaxAge() max age} is equal to the expected value.
* @param name the name of the cookie
* @param expected the expected max age of the cookie
*/
@ -123,9 +119,8 @@ public class CookieMapAssert extends AbstractMapAssert<CookieMapAssert, Map<Stri
}
/**
* Verify that the actual cookies contain a cookie with the given
* {@code name} whose {@linkplain Cookie#getPath() path} is equal to
* the given one.
* Verify that the actual cookies contain a cookie with the given {@code name}
* whose {@linkplain Cookie#getPath() path} is equal to the expected value.
* @param name the name of the cookie
* @param expected the expected path of the cookie
*/
@ -135,11 +130,10 @@ public class CookieMapAssert extends AbstractMapAssert<CookieMapAssert, Map<Stri
}
/**
* Verify that the actual cookies contain a cookie with the given
* {@code name} whose {@linkplain Cookie#getDomain() domain} is equal to
* the given one.
* Verify that the actual cookies contain a cookie with the given {@code name}
* whose {@linkplain Cookie#getDomain() domain} is equal to the expected value.
* @param name the name of the cookie
* @param expected the expected path of the cookie
* @param expected the expected domain of the cookie
*/
public CookieMapAssert hasDomain(String name, String expected) {
return hasCookieSatisfying(name, cookie ->
@ -147,9 +141,9 @@ public class CookieMapAssert extends AbstractMapAssert<CookieMapAssert, Map<Stri
}
/**
* Verify that the actual cookies contain a cookie with the given
* {@code name} whose {@linkplain Cookie#getSecure() secure flag} is equal
* to the given one.
* Verify that the actual cookies contain a cookie with the given {@code name}
* whose {@linkplain Cookie#getSecure() secure flag} is equal to the expected
* value.
* @param name the name of the cookie
* @param expected whether the cookie is secure
*/
@ -159,9 +153,9 @@ public class CookieMapAssert extends AbstractMapAssert<CookieMapAssert, Map<Stri
}
/**
* Verify that the actual cookies contain a cookie with the given
* {@code name} whose {@linkplain Cookie#isHttpOnly() http only flag} is
* equal to the given one.
* Verify that the actual cookies contain a cookie with the given {@code name}
* whose {@linkplain Cookie#isHttpOnly() http only flag} is equal to the
* expected value.
* @param name the name of the cookie
* @param expected whether the cookie is http only
*/

View File

@ -46,9 +46,9 @@ public class HandlerResultAssert extends AbstractObjectAssert<HandlerResultAsser
/**
* Return a new {@linkplain MethodAssert assertion} object that uses
* the {@link Method} that handles the request as the object to test.
* Verify first that the handler is a {@linkplain #isMethodHandler() method
* handler}.
* Example: <pre><code class='java'>
* <p>Verifies first that the handler is a {@linkplain #isMethodHandler()
* method handler}.
* <p>Example: <pre><code class='java'>
* // Check that a GET to "/greet" is invoked on a "handleGreet" method name
* assertThat(mvc.perform(get("/greet")).handler().method().hasName("sayGreet");
* </code></pre>
@ -67,14 +67,15 @@ public class HandlerResultAssert extends AbstractObjectAssert<HandlerResultAsser
/**
* Verify that the handler is managed by the given {@code handlerMethod}.
* This creates a "mock" for the given {@code controllerType} and record the
* method invocation in the {@code handlerMethod}. The arguments used by the
* target method invocation can be {@code null} as the purpose of the mock
* <p>This creates a "mock" for the given {@code controllerType} and records
* the method invocation in the {@code handlerMethod}. The arguments used by
* the target method invocation can be {@code null} as the purpose of the mock
* is to identify the method that was invoked.
* Example: <pre><code class='java'>
* <p>Example: <pre><code class='java'>
* // If the method has a return type, you can return the result of the invocation
* assertThat(mvc.perform(get("/greet")).handler().isInvokedOn(
* GreetController.class, controller -> controller.sayGreet());
*
* // If the method has a void return type, the controller should be returned
* assertThat(mvc.perform(post("/persons/")).handler().isInvokedOn(
* PersonController.class, controller -> controller.createPerson(null, null));
@ -95,7 +96,7 @@ public class HandlerResultAssert extends AbstractObjectAssert<HandlerResultAsser
/**
* Verify that the handler is of the given {@code type}. For a controller
* method, this is the type of the controller.
* Example: <pre><code class='java'>
* <p>Example: <pre><code class='java'>
* // Check that a GET to "/greet" is managed by GreetController
* assertThat(mvc.perform(get("/greet")).handler().hasType(GreetController.class);
* </code></pre>

View File

@ -51,7 +51,7 @@ public class ModelAssert extends AbstractMapAssert<ModelAssert, Map<String, Obje
* Return a new {@linkplain AbstractBindingResultAssert assertion} object
* that uses the {@link BindingResult} with the given {@code name} as the
* object to test.
* Examples: <pre><code class='java'>
* <p>Example: <pre><code class='java'>
* // Check that the "person" attribute in the model has 2 errors:
* assertThat(...).model().extractingBindingResult("person").hasErrorsCount(2);
* </code></pre>
@ -85,23 +85,23 @@ public class ModelAssert extends AbstractMapAssert<ModelAssert, Map<String, Obje
}
/**
* Verify that the actual model contain the attributes with the given
* {@code names}, and that these attributes have each at least one error.
* Verify that the actual model contains the attributes with the given
* {@code names}, and that each of these attributes has each at least one error.
* @param names the expected names of attributes with errors
*/
public ModelAssert hasAttributeErrors(String... names) {
return assertAttributes(names, BindingResult::hasErrors,
"to have attribute errors for", "these attributes do not have any error");
"to have attribute errors for", "these attributes do not have any errors");
}
/**
* Verify that the actual model contain the attributes with the given
* {@code names}, and that these attributes do not have any error.
* Verify that the actual model contains the attributes with the given
* {@code names}, and that none of these attributes has an error.
* @param names the expected names of attributes without errors
*/
public ModelAssert doesNotHaveAttributeErrors(String... names) {
return assertAttributes(names, Predicate.not(BindingResult::hasErrors),
"to have attribute without errors for", "these attributes have at least an error");
"to have attribute without errors for", "these attributes have at least one error");
}
private ModelAssert assertAttributes(String[] names, Predicate<BindingResult> condition,

View File

@ -102,7 +102,7 @@ public class MvcResultAssert extends AbstractMockHttpServletResponseAssert<MvcRe
* Return a new {@linkplain HandlerResultAssert assertion} object that uses
* the handler as the object to test. For a method invocation on a
* controller, this is relative method handler
* Example: <pre><code class='java'>
* <p>Example: <pre><code class='java'>
* // Check that a GET to "/greet" is invoked on a "handleGreet" method name
* assertThat(mvc.perform(get("/greet")).handler().method().hasName("sayGreet");
* </code></pre>

View File

@ -62,12 +62,14 @@ public class ResponseBodyAssert extends AbstractByteArrayAssert<ResponseBodyAsse
}
/**
* 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'>
* Return a new {@linkplain JsonContentAssert assertion} object that provides
* support for {@linkplain org.skyscreamer.jsonassert.JSONCompareMode JSON
* assert} comparisons against expected JSON input which can be loaded from
* the classpath.
* <p>This method only supports absolute locations for JSON documents loaded
* from the classpath. Consider using {@link #json(Class)} to load JSON
* documents relative to a given class.
* <p>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()
@ -79,18 +81,19 @@ public class ResponseBodyAssert extends AbstractByteArrayAssert<ResponseBodyAsse
}
/**
* 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:
* Return a new {@linkplain JsonContentAssert assertion} object that provides
* support for {@linkplain org.skyscreamer.jsonassert.JSONCompareMode JSON
* assert} comparisons against expected JSON input which can be loaded from
* the classpath.
* <p>Locations for JSON documents can be absolute using a leading slash, or
* relative to the given {@code resourceLoadClass}.
* <p>Example: <pre><code class='java'>
* // Check that the response is strictly equal to the content of the
* // specified file located in the same package as the PersonController:
* assertThat(...).body().json(PersonController.class)
* .isStrictlyEqualToJson("person-created.json");
* </code></pre>
* @param resourceLoadClass the class used to load relative json documents
* @param resourceLoadClass the class used to load relative JSON documents
* @see ClassPathResource#ClassPathResource(String, Class)
*/
public JsonContentAssert json(@Nullable Class<?> resourceLoadClass) {
@ -98,8 +101,8 @@ public class ResponseBodyAssert extends AbstractByteArrayAssert<ResponseBodyAsse
}
/**
* 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
* Verify that the response body is equal to the given {@link String}.
* <p>Converts 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()
@ -110,8 +113,8 @@ public class ResponseBodyAssert extends AbstractByteArrayAssert<ResponseBodyAsse
}
/**
* Override that uses the character encoding of {@link HttpServletResponse} to
* convert the byte[] to a String, rather than the platform's default charset.
* Override that uses the character encoding of the {@link HttpServletResponse}
* to convert the byte[] to a String, rather than the platform's default charset.
*/
@Override
public AbstractStringAssert<?> asString() {

View File

@ -208,7 +208,8 @@ class JsonPathAssertTests {
@Test
void convertToWithoutHttpMessageConverterShouldFail() {
JsonPathValueAssert path = assertThat(forJson(SIMPSONS)).extractingPath("$.familyMembers[0]");
assertThatIllegalStateException().isThrownBy(() -> path.convertTo(Member.class))
assertThatIllegalStateException()
.isThrownBy(() -> path.convertTo(Member.class))
.withMessage("No JSON message converter available to convert {name=Homer}");
}
@ -296,7 +297,7 @@ class JsonPathAssertTests {
private Consumer<AssertionError> hasFailedToNotMatchPath(String expression) {
return error -> assertThat(error.getMessage()).containsSubsequence("Expecting:",
"To not match JSON path:", "\"" + expression + "\"");
"Not to match JSON path:", "\"" + expression + "\"");
}

View File

@ -51,21 +51,21 @@ class UriAssertTests {
}
@Test
void matchPattern() {
assertThat("/orders/1").matchPattern("/orders/*");
void matchesPattern() {
assertThat("/orders/1").matchesPattern("/orders/*");
}
@Test
void matchPatternWithNonValidPattern() {
void matchesPatternWithNonValidPattern() {
assertThatExceptionOfType(AssertionError.class)
.isThrownBy(() -> assertThat("/orders/1").matchPattern("/orders/"))
.isThrownBy(() -> assertThat("/orders/1").matchesPattern("/orders/"))
.withMessage("'/orders/' is not an Ant-style path pattern");
}
@Test
void matchPatternWithWrongValue() {
void matchesPatternWithWrongValue() {
assertThatExceptionOfType(AssertionError.class)
.isThrownBy(() -> assertThat("/orders/1").matchPattern("/resources/*"))
.isThrownBy(() -> assertThat("/orders/1").matchesPattern("/resources/*"))
.withMessageContainingAll("Test URI", "/resources/*", "/orders/1");
}

View File

@ -28,6 +28,7 @@ import org.junit.jupiter.api.Test;
import org.springframework.mock.web.MockHttpServletRequest;
import static java.util.Map.entry;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
/**
* Tests for {@link AbstractHttpServletRequestAssert}.
@ -52,7 +53,7 @@ public class AbstractHttpServletRequestAssertTests {
@Test
void attributesWithWrongKey() {
HttpServletRequest request = createRequest(Map.of("one", 1));
Assertions.assertThatExceptionOfType(AssertionError.class)
assertThatExceptionOfType(AssertionError.class)
.isThrownBy(() -> assertThat(request).attributes().containsKey("two"))
.withMessageContainingAll("Request Attributes", "two", "one");
}
@ -80,7 +81,7 @@ public class AbstractHttpServletRequestAssertTests {
@Test
void sessionAttributesWithWrongKey() {
HttpServletRequest request = createRequest(Map.of("one", 1));
Assertions.assertThatExceptionOfType(AssertionError.class)
assertThatExceptionOfType(AssertionError.class)
.isThrownBy(() -> assertThat(request).sessionAttributes().containsKey("two"))
.withMessageContainingAll("Session Attributes", "two", "one");
}
@ -107,7 +108,7 @@ public class AbstractHttpServletRequestAssertTests {
void hasAsyncStartedTrueWithFalse() {
MockHttpServletRequest request = new MockHttpServletRequest();
request.setAsyncStarted(false);
Assertions.assertThatExceptionOfType(AssertionError.class)
assertThatExceptionOfType(AssertionError.class)
.isThrownBy(() -> assertThat(request).hasAsyncStarted(true))
.withMessage("Async expected to have started");
}
@ -123,12 +124,13 @@ public class AbstractHttpServletRequestAssertTests {
void hasAsyncStartedFalseWithTrue() {
MockHttpServletRequest request = new MockHttpServletRequest();
request.setAsyncStarted(true);
Assertions.assertThatExceptionOfType(AssertionError.class)
assertThatExceptionOfType(AssertionError.class)
.isThrownBy(() -> assertThat(request).hasAsyncStarted(false))
.withMessage("Async expected to not have started");
.withMessage("Async expected not to have started");
}
private static ResponseAssert assertThat(HttpServletRequest response) {
return new ResponseAssert(response);
}
@ -140,4 +142,5 @@ public class AbstractHttpServletRequestAssertTests {
super(actual, ResponseAssert.class);
}
}
}

View File

@ -73,7 +73,8 @@ class AbstractHttpServletResponseAssertTests {
@Test
void hasStatusWithWrongCode() {
MockHttpServletResponse response = createResponse(200);
assertThatExceptionOfType(AssertionError.class).isThrownBy(() -> assertThat(response).hasStatus(300))
assertThatExceptionOfType(AssertionError.class)
.isThrownBy(() -> assertThat(response).hasStatus(300))
.withMessageContainingAll("HTTP status code", "200", "300");
}
@ -117,6 +118,7 @@ class AbstractHttpServletResponseAssertTests {
}
}
private static ResponseAssert assertThat(HttpServletResponse response) {
return new ResponseAssert(response);
}

View File

@ -18,14 +18,15 @@ 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;
import static java.nio.charset.StandardCharsets.UTF_8;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
/**
* Tests for {@link AbstractMockHttpServletResponseAssert}.
*
@ -33,10 +34,12 @@ import org.springframework.mock.web.MockHttpServletResponse;
*/
public class AbstractMockHttpServletResponseAssertTests {
private MockHttpServletResponse response = new MockHttpServletResponse();
@Test
void hasForwardedUrl() {
String forwardedUrl = "https://example.com/42";
MockHttpServletResponse response = new MockHttpServletResponse();
response.setForwardedUrl(forwardedUrl);
assertThat(response).hasForwardedUrl(forwardedUrl);
}
@ -44,9 +47,8 @@ public class AbstractMockHttpServletResponseAssertTests {
@Test
void hasForwardedUrlWithWrongValue() {
String forwardedUrl = "https://example.com/42";
MockHttpServletResponse response = new MockHttpServletResponse();
response.setForwardedUrl(forwardedUrl);
Assertions.assertThatExceptionOfType(AssertionError.class)
assertThatExceptionOfType(AssertionError.class)
.isThrownBy(() -> assertThat(response).hasForwardedUrl("another"))
.withMessageContainingAll("Forwarded URL", forwardedUrl, "another");
}
@ -54,7 +56,6 @@ public class AbstractMockHttpServletResponseAssertTests {
@Test
void hasRedirectedUrl() {
String redirectedUrl = "https://example.com/42";
MockHttpServletResponse response = new MockHttpServletResponse();
response.addHeader(HttpHeaders.LOCATION, redirectedUrl);
assertThat(response).hasRedirectedUrl(redirectedUrl);
}
@ -62,26 +63,23 @@ public class AbstractMockHttpServletResponseAssertTests {
@Test
void hasRedirectedUrlWithWrongValue() {
String redirectedUrl = "https://example.com/42";
MockHttpServletResponse response = new MockHttpServletResponse();
response.addHeader(HttpHeaders.LOCATION, redirectedUrl);
Assertions.assertThatExceptionOfType(AssertionError.class)
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();
byte[] bytes = "OK".getBytes(UTF_8);
response.getWriter().write("OK");
response.setContentType(StandardCharsets.UTF_8.name());
response.setContentType(UTF_8.name());
assertThat(response).body().isEqualTo(bytes);
}
@ -103,4 +101,5 @@ public class AbstractMockHttpServletResponseAssertTests {
}
}
}

View File

@ -309,15 +309,15 @@ public class AssertableMockMvcIntegrationTests {
@Test
void doesNotHaveUnresolvedExceptionWithUnresolvedException() {
assertThatExceptionOfType(AssertionError.class).isThrownBy(() ->
assertThat(perform(get("/error/1"))).doesNotHaveUnresolvedException())
assertThatExceptionOfType(AssertionError.class)
.isThrownBy(() -> assertThat(perform(get("/error/1"))).doesNotHaveUnresolvedException())
.withMessage("Expecting request to have succeeded but it has failed");
}
@Test
void hasUnresolvedExceptionWithoutUnresolvedException() {
assertThatExceptionOfType(AssertionError.class).isThrownBy(() ->
assertThat(perform(get("/greet"))).hasUnresolvedException())
assertThatExceptionOfType(AssertionError.class)
.isThrownBy(() -> assertThat(perform(get("/greet"))).hasUnresolvedException())
.withMessage("Expecting request to have failed but it has succeeded");
}
@ -330,8 +330,8 @@ public class AssertableMockMvcIntegrationTests {
@Test
void unresolvedExceptionWithSuccessfulRequest() {
assertThatExceptionOfType(AssertionError.class).isThrownBy(() ->
assertThat(perform(get("/greet"))).unresolvedException())
assertThatExceptionOfType(AssertionError.class)
.isThrownBy(() -> assertThat(perform(get("/greet"))).unresolvedException())
.withMessage("Expecting request to have failed but it has succeeded");
}
@ -439,7 +439,7 @@ public class AssertableMockMvcIntegrationTests {
}
@Test
void satisfiesAllowAdditionalAssertions() {
void satisfiesAllowsAdditionalAssertions() {
assertThat(this.mockMvc.perform(get("/greet"))).satisfies(result -> {
assertThat(result).isInstanceOf(MvcResult.class);
assertThat(result).hasStatusOk();
@ -477,7 +477,6 @@ public class AssertableMockMvcIntegrationTests {
@Import({ TestController.class, PersonController.class, AsyncController.class,
SessionController.class, ErrorController.class })
static class WebConfiguration {
}
@RestController
@ -515,7 +514,6 @@ public class AssertableMockMvcIntegrationTests {
}
}
@RestController
static class AsyncController {
@ -552,7 +550,6 @@ public class AssertableMockMvcIntegrationTests {
public String validation(@PathVariable @Size(max = 4) String id) {
return "Hello " + id;
}
}
}

View File

@ -29,7 +29,6 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.converter.GenericHttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.mock.web.MockServletContext;
import org.springframework.test.json.JsonPathAssert;
@ -40,8 +39,8 @@ import org.springframework.web.context.support.GenericWebApplicationContext;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
@ -58,10 +57,10 @@ class AssertableMockMvcTests {
private static final MappingJackson2HttpMessageConverter jsonHttpMessageConverter =
new MappingJackson2HttpMessageConverter(new ObjectMapper());
@Test
void createShouldRejectNullMockMvc() {
assertThatThrownBy(() -> AssertableMockMvc.create(null))
.isInstanceOf(IllegalArgumentException.class);
assertThatIllegalArgumentException().isThrownBy(() -> AssertableMockMvc.create(null));
}
@Test
@ -122,8 +121,7 @@ class AssertableMockMvcTests {
void withHttpMessageConverterDetectsJsonConverter() {
MappingJackson2HttpMessageConverter converter = spy(jsonHttpMessageConverter);
AssertableMockMvc mockMvc = AssertableMockMvc.of(HelloController.class)
.withHttpMessageConverters(List.of(mock(GenericHttpMessageConverter.class),
mock(GenericHttpMessageConverter.class), converter));
.withHttpMessageConverters(List.of(mock(), mock(), converter));
assertThat(mockMvc.perform(get("/json"))).hasStatusOk().body().jsonPath()
.extractingPath("$").convertTo(Message.class).satisfies(message -> {
assertThat(message.message()).isEqualTo("Hello World");
@ -136,14 +134,13 @@ class AssertableMockMvcTests {
void performWithUnresolvedExceptionSetsException() {
AssertableMockMvc mockMvc = AssertableMockMvc.of(HelloController.class);
AssertableMvcResult result = mockMvc.perform(get("/error"));
assertThat(result.getUnresolvedException()).isNotNull().isInstanceOf(ServletException.class)
assertThat(result.getUnresolvedException()).isInstanceOf(ServletException.class)
.cause().isInstanceOf(IllegalStateException.class).hasMessage("Expected");
assertThat(result).hasFieldOrPropertyWithValue("target", null);
}
private GenericWebApplicationContext create(Class<?>... classes) {
GenericWebApplicationContext applicationContext = new GenericWebApplicationContext(
new MockServletContext());
GenericWebApplicationContext applicationContext = new GenericWebApplicationContext(new MockServletContext());
AnnotationConfigUtils.registerAnnotationConfigProcessors(applicationContext);
for (Class<?> beanClass : classes) {
applicationContext.registerBean(beanClass);
@ -189,22 +186,23 @@ class AssertableMockMvcTests {
private record Message(String message, int counter) {}
@RestController
private static class CounterController {
static class CounterController {
private final AtomicInteger counter;
public CounterController(AtomicInteger counter) {
this.counter = counter;
}
public CounterController() {
CounterController() {
this(new AtomicInteger());
}
CounterController(AtomicInteger counter) {
this.counter = counter;
}
@PostMapping("/increase")
public String increase() {
String increase() {
int value = this.counter.incrementAndGet();
return "counter " + value;
}
}
}

View File

@ -16,7 +16,6 @@
package org.springframework.test.web.servlet.assertj;
import java.time.Duration;
import java.util.List;
@ -53,130 +52,130 @@ class CookieMapAssertTests {
@Test
void containsCookieWhenCookieExistsShouldPass() {
assertThat(forCookies()).containsCookie("framework");
cookies().containsCookie("framework");
}
@Test
void containsCookieWhenCookieMissingShouldFail() {
assertThatExceptionOfType(AssertionError.class).isThrownBy(() ->
assertThat(forCookies()).containsCookie("missing"));
cookies().containsCookie("missing"));
}
@Test
void containsCookiesWhenCookiesExistShouldPass() {
assertThat(forCookies()).containsCookies("framework", "age");
cookies().containsCookies("framework", "age");
}
@Test
void containsCookiesWhenCookieMissingShouldFail() {
assertThatExceptionOfType(AssertionError.class).isThrownBy(() ->
assertThat(forCookies()).containsCookies("framework", "missing"));
cookies().containsCookies("framework", "missing"));
}
@Test
void doesNotContainCookieWhenCookieMissingShouldPass() {
assertThat(forCookies()).doesNotContainCookie("missing");
cookies().doesNotContainCookie("missing");
}
@Test
void doesNotContainCookieWhenCookieExistsShouldFail() {
assertThatExceptionOfType(AssertionError.class).isThrownBy(() ->
assertThat(forCookies()).doesNotContainCookie("framework"));
cookies().doesNotContainCookie("framework"));
}
@Test
void doesNotContainCookiesWhenCookiesMissingShouldPass() {
assertThat(forCookies()).doesNotContainCookies("missing", "missing2");
cookies().doesNotContainCookies("missing", "missing2");
}
@Test
void doesNotContainCookiesWhenAtLeastOneCookieExistShouldFail() {
assertThatExceptionOfType(AssertionError.class).isThrownBy(() ->
assertThat(forCookies()).doesNotContainCookies("missing", "framework"));
cookies().doesNotContainCookies("missing", "framework"));
}
@Test
void hasValueEqualsWhenCookieValueMatchesShouldPass() {
assertThat(forCookies()).hasValue("framework", "spring");
cookies().hasValue("framework", "spring");
}
@Test
void hasValueEqualsWhenCookieValueDiffersShouldFail() {
assertThatExceptionOfType(AssertionError.class).isThrownBy(() ->
assertThat(forCookies()).hasValue("framework", "other"));
cookies().hasValue("framework", "other"));
}
@Test
void hasCookieSatisfyingWhenCookieValueMatchesShouldPass() {
assertThat(forCookies()).hasCookieSatisfying("framework", cookie ->
cookies().hasCookieSatisfying("framework", cookie ->
assertThat(cookie.getValue()).startsWith("spr"));
}
@Test
void hasCookieSatisfyingWhenCookieValueDiffersShouldFail() {
assertThatExceptionOfType(AssertionError.class).isThrownBy(() ->
assertThat(forCookies()).hasCookieSatisfying("framework", cookie ->
cookies().hasCookieSatisfying("framework", cookie ->
assertThat(cookie.getValue()).startsWith("not")));
}
@Test
void hasMaxAgeWhenCookieAgeMatchesShouldPass() {
assertThat(forCookies()).hasMaxAge("age", Duration.ofMinutes(20));
cookies().hasMaxAge("age", Duration.ofMinutes(20));
}
@Test
void hasMaxAgeWhenCookieAgeDiffersShouldFail() {
assertThatExceptionOfType(AssertionError.class).isThrownBy(() ->
assertThat(forCookies()).hasMaxAge("age", Duration.ofMinutes(30)));
cookies().hasMaxAge("age", Duration.ofMinutes(30)));
}
@Test
void pathWhenCookiePathMatchesShouldPass() {
assertThat(forCookies()).hasPath("path", "/spring");
cookies().hasPath("path", "/spring");
}
@Test
void pathWhenCookiePathDiffersShouldFail() {
assertThatExceptionOfType(AssertionError.class).isThrownBy(() ->
assertThat(forCookies()).hasPath("path", "/other"));
cookies().hasPath("path", "/other"));
}
@Test
void hasDomainWhenCookieDomainMatchesShouldPass() {
assertThat(forCookies()).hasDomain("domain", "spring.io");
cookies().hasDomain("domain", "spring.io");
}
@Test
void hasDomainWhenCookieDomainDiffersShouldFail() {
assertThatExceptionOfType(AssertionError.class).isThrownBy(() ->
assertThat(forCookies()).hasDomain("domain", "example.org"));
cookies().hasDomain("domain", "example.org"));
}
@Test
void isSecureWhenCookieSecureMatchesShouldPass() {
assertThat(forCookies()).isSecure("framework", true);
cookies().isSecure("framework", true);
}
@Test
void isSecureWhenCookieSecureDiffersShouldFail() {
assertThatExceptionOfType(AssertionError.class).isThrownBy(() ->
assertThat(forCookies()).isSecure("domain", true));
cookies().isSecure("domain", true));
}
@Test
void isHttpOnlyWhenCookieHttpOnlyMatchesShouldPass() {
assertThat(forCookies()).isHttpOnly("framework", true);
cookies().isHttpOnly("framework", true);
}
@Test
void isHttpOnlyWhenCookieHttpOnlyDiffersShouldFail() {
assertThatExceptionOfType(AssertionError.class).isThrownBy(() ->
assertThat(forCookies()).isHttpOnly("domain", true));
cookies().isHttpOnly("domain", true));
}
private AssertProvider<CookieMapAssert> forCookies() {
return () -> new CookieMapAssert(cookies);
private static CookieMapAssert cookies() {
return assertThat((AssertProvider<CookieMapAssert>) () -> new CookieMapAssert(cookies));
}
}

View File

@ -71,8 +71,7 @@ class HandlerResultAssertTests {
@Test
void method() {
assertThat(handlerMethod(new TestController(), "greet")).method().isEqualTo(
ReflectionUtils.findMethod(TestController.class, "greet"));
assertThat(handlerMethod(new TestController(), "greet")).method().isEqualTo(method(TestController.class, "greet"));
}
@Test
@ -126,7 +125,7 @@ class HandlerResultAssertTests {
}
@RestController
public static class TestController {
static class TestController {
@GetMapping("/greet")
public ResponseEntity<String> greet() {

View File

@ -45,7 +45,8 @@ class ModelAssertTests {
@Test
void hasErrorsWithNoError() {
AssertProvider<ModelAssert> actual = forModel(new TestBean(), Map.of("name", "John", "age", "42"));
assertThatExceptionOfType(AssertionError.class).isThrownBy(() -> assertThat(actual).hasErrors())
assertThatExceptionOfType(AssertionError.class)
.isThrownBy(() -> assertThat(actual).hasErrors())
.withMessageContainingAll("John", "to have at least one error");
}
@ -57,7 +58,8 @@ class ModelAssertTests {
@Test
void doesNotHaveErrorsWithError() {
AssertProvider<ModelAssert> actual = forModel(new TestBean(), Map.of("name", "John", "age", "4x"));
assertThatExceptionOfType(AssertionError.class).isThrownBy(() -> assertThat(actual).doesNotHaveErrors())
assertThatExceptionOfType(AssertionError.class)
.isThrownBy(() -> assertThat(actual).doesNotHaveErrors())
.withMessageContainingAll("John", "to not have an error, but got 1");
}
@ -73,8 +75,8 @@ class ModelAssertTests {
Map<String, Object> model = new HashMap<>();
augmentModel(model, "person", new TestBean(), Map.of("name", "John", "age", "42"));
AssertProvider<ModelAssert> actual = forModel(model);
assertThatExceptionOfType(AssertionError.class).isThrownBy(
() -> assertThat(actual).extractingBindingResult("user"))
assertThatExceptionOfType(AssertionError.class)
.isThrownBy(() -> assertThat(actual).extractingBindingResult("user"))
.withMessageContainingAll("to have a binding result for attribute 'user'");
}
@ -94,10 +96,10 @@ class ModelAssertTests {
augmentModel(model, "valid", new TestBean(), Map.of("name", "second"));
augmentModel(model, "wrong2", new TestBean(), Map.of("name", "third", "touchy", "invalid.name"));
AssertProvider<ModelAssert> actual = forModel(model);
assertThatExceptionOfType(AssertionError.class).isThrownBy(
() -> assertThat(actual).hasAttributeErrors("wrong1", "valid"))
assertThatExceptionOfType(AssertionError.class)
.isThrownBy(() -> assertThat(actual).hasAttributeErrors("wrong1", "valid"))
.withMessageContainingAll("to have attribute errors for:", "wrong1, valid",
"but these attributes do not have any error:", "valid");
"but these attributes do not have any errors:", "valid");
}
@Test
@ -107,11 +109,11 @@ class ModelAssertTests {
augmentModel(model, "valid", new TestBean(), Map.of("name", "second"));
augmentModel(model, "wrong2", new TestBean(), Map.of("name", "third", "touchy", "invalid.name"));
AssertProvider<ModelAssert> actual = forModel(model);
assertThatExceptionOfType(AssertionError.class).isThrownBy(
() -> assertThat(actual).hasAttributeErrors("wrong1", "unknown", "valid"))
assertThatExceptionOfType(AssertionError.class)
.isThrownBy(() -> assertThat(actual).hasAttributeErrors("wrong1", "unknown", "valid"))
.withMessageContainingAll("to have attribute errors for:", "wrong1, unknown, valid",
"but could not find these attributes:", "unknown",
"and these attributes do not have any error:", "valid");
"and these attributes do not have any errors:", "valid");
}
@Test
@ -130,10 +132,10 @@ class ModelAssertTests {
augmentModel(model, "wrong", new TestBean(), Map.of("name", "second", "age", "4x"));
augmentModel(model, "valid2", new TestBean(), Map.of("name", "third"));
AssertProvider<ModelAssert> actual = forModel(model);
assertThatExceptionOfType(AssertionError.class).isThrownBy(
() -> assertThat(actual).doesNotHaveAttributeErrors("valid1", "wrong"))
assertThatExceptionOfType(AssertionError.class)
.isThrownBy(() -> assertThat(actual).doesNotHaveAttributeErrors("valid1", "wrong"))
.withMessageContainingAll("to have attribute without errors for:", "valid1, wrong",
"but these attributes have at least an error:", "wrong");
"but these attributes have at least one error:", "wrong");
}
@Test
@ -143,11 +145,11 @@ class ModelAssertTests {
augmentModel(model, "wrong", new TestBean(), Map.of("name", "second", "age", "4x"));
augmentModel(model, "valid2", new TestBean(), Map.of("name", "third"));
AssertProvider<ModelAssert> actual = forModel(model);
assertThatExceptionOfType(AssertionError.class).isThrownBy(
() -> assertThat(actual).doesNotHaveAttributeErrors("valid1", "unknown", "wrong"))
assertThatExceptionOfType(AssertionError.class)
.isThrownBy(() -> assertThat(actual).doesNotHaveAttributeErrors("valid1", "unknown", "wrong"))
.withMessageContainingAll("to have attribute without errors for:", "valid1, unknown, wrong",
"but could not find these attributes:", "unknown",
"and these attributes have at least an error:", "wrong");
"and these attributes have at least one error:", "wrong");
}
private AssertProvider<ModelAssert> forModel(Map<String, Object> model) {

View File

@ -19,7 +19,6 @@ 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;
@ -27,6 +26,7 @@ import org.junit.jupiter.api.Test;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.test.json.JsonContent;
import static java.nio.charset.StandardCharsets.UTF_8;
import static org.assertj.core.api.Assertions.assertThat;
/**
@ -40,8 +40,8 @@ class ResponseBodyAssertTests {
@Test
void isEqualToWithByteArray() {
MockHttpServletResponse response = createResponse("hello");
response.setCharacterEncoding(StandardCharsets.UTF_8.name());
assertThat(fromResponse(response)).isEqualTo("hello".getBytes(StandardCharsets.UTF_8));
response.setCharacterEncoding(UTF_8.name());
assertThat(fromResponse(response)).isEqualTo("hello".getBytes(UTF_8));
}
@Test