Browse Source

Add support for converting json values using AssertFactory

This commit benefits from a feature introduced in AssertJ 3.26.0, see
https://github.com/assertj/assertj/pull/3377.

This allows to use any AssertFactory and convert the actual value to
the type the factory manages. Previously, we were using
ParameterizedTypeReference to express the type with its generic
signature but the returned assert object would not be narrowed to the
converted type.

Thanks to this change, we can request to convert the actual value to
`InstanceOfAssertFactories.list(Member.class)` and get a `ListAssert`
of `Member` as a result, rather than an `ObjectAssert` of `List<User>`.

Thanks very much to @scordio for his efforts.

Closes gh-32953
pull/32957/head
Stéphane Nicoll 2 years ago
parent
commit
aa4b226a22
  1. 27
      spring-test/src/main/java/org/springframework/test/json/AbstractJsonValueAssert.java
  2. 6
      spring-test/src/test/java/org/springframework/test/json/AbstractJsonContentAssertTests.java
  3. 6
      spring-test/src/test/java/org/springframework/test/json/JsonPathValueAssertTests.java

27
spring-test/src/main/java/org/springframework/test/json/AbstractJsonValueAssert.java

@ -20,16 +20,18 @@ import java.lang.reflect.Type; @@ -20,16 +20,18 @@ import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;
import org.assertj.core.api.AbstractAssert;
import org.assertj.core.api.AbstractBooleanAssert;
import org.assertj.core.api.AbstractMapAssert;
import org.assertj.core.api.AbstractObjectAssert;
import org.assertj.core.api.AbstractStringAssert;
import org.assertj.core.api.AssertFactory;
import org.assertj.core.api.Assertions;
import org.assertj.core.api.InstanceOfAssertFactories;
import org.assertj.core.api.ObjectArrayAssert;
import org.assertj.core.error.BasicErrorMessageFactory;
import org.assertj.core.internal.Failures;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.core.ResolvableType;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.MediaType;
@ -152,16 +154,23 @@ public abstract class AbstractJsonValueAssert<SELF extends AbstractJsonValueAsse @@ -152,16 +154,23 @@ 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
* assertion} object narrowed to that type.
* @param target the {@linkplain ParameterizedTypeReference parameterized
* type} to convert the actual value to
* Verify that the actual value can be converted to an instance of the type
* defined by the given {@link AssertFactory} and return a new Assert narrowed
* to that type.
* <p>{@link InstanceOfAssertFactories} provides static factories for all the
* types supported by {@link Assertions#assertThat}. Additional factories can
* be created by implementing {@link AssertFactory}.
* <p>Example: <pre><code class="java">
* // Check that the json value is an array of 3 users
* assertThat(jsonValue).convertTo(InstanceOfAssertFactories.list(User.class))
* hasSize(3); // ListAssert of User
* </code></pre>
* @param assertFactory the {@link AssertFactory} to use to produce a narrowed
* Assert for the type that it defines.
*/
public <T> AbstractObjectAssert<?, T> convertTo(ParameterizedTypeReference<T> target) {
public <ASSERT extends AbstractAssert<?, ?>> ASSERT convertTo(AssertFactory<?, ASSERT> assertFactory) {
isNotNull();
T value = convertToTargetType(target.getType());
return Assertions.assertThat(value);
return assertFactory.createAssert(this::convertToTargetType);
}
/**

6
spring-test/src/test/java/org/springframework/test/json/AbstractJsonContentAssertTests.java

@ -28,6 +28,7 @@ import java.util.stream.Stream; @@ -28,6 +28,7 @@ import java.util.stream.Stream;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.assertj.core.api.AssertProvider;
import org.assertj.core.api.InstanceOfAssertFactories;
import org.json.JSONException;
import org.json.JSONObject;
import org.junit.jupiter.api.Nested;
@ -42,7 +43,6 @@ import org.skyscreamer.jsonassert.JSONCompareMode; @@ -42,7 +43,6 @@ import org.skyscreamer.jsonassert.JSONCompareMode;
import org.skyscreamer.jsonassert.JSONCompareResult;
import org.skyscreamer.jsonassert.comparator.JSONComparator;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.FileSystemResource;
@ -286,8 +286,8 @@ class AbstractJsonContentAssertTests { @@ -286,8 +286,8 @@ class AbstractJsonContentAssertTests {
void convertArrayToParameterizedType() {
assertThat(forJson(SIMPSONS, jsonHttpMessageConverter))
.extractingPath("$.familyMembers")
.convertTo(new ParameterizedTypeReference<List<Member>>() {})
.satisfies(family -> assertThat(family).hasSize(5).element(0).isEqualTo(new Member("Homer")));
.convertTo(InstanceOfAssertFactories.list(Member.class))
.hasSize(5).element(0).isEqualTo(new Member("Homer"));
}
@Test

6
spring-test/src/test/java/org/springframework/test/json/JsonPathValueAssertTests.java

@ -28,7 +28,6 @@ import org.assertj.core.data.Offset; @@ -28,7 +28,6 @@ import org.assertj.core.data.Offset;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.lang.Nullable;
import org.springframework.util.StringUtils;
@ -231,9 +230,8 @@ class JsonPathValueAssertTests { @@ -231,9 +230,8 @@ class JsonPathValueAssertTests {
Map<?, ?> user2 = Map.of("id", 5678, "name", "Sarah", "active", false);
Map<?, ?> user3 = Map.of("id", 9012, "name", "Sophia", "active", true);
assertThat(forValue(List.of(user1, user2, user3)))
.convertTo(new ParameterizedTypeReference<List<User>>() {})
.satisfies(users -> assertThat(users).hasSize(3).extracting("name")
.containsExactly("John", "Sarah", "Sophia"));
.convertTo(InstanceOfAssertFactories.list(User.class))
.hasSize(3).extracting("name").containsExactly("John", "Sarah", "Sophia");
}
@Test

Loading…
Cancel
Save