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;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import org.assertj.core.api.AbstractAssert;
import org.assertj.core.api.AbstractBooleanAssert; import org.assertj.core.api.AbstractBooleanAssert;
import org.assertj.core.api.AbstractMapAssert; import org.assertj.core.api.AbstractMapAssert;
import org.assertj.core.api.AbstractObjectAssert; import org.assertj.core.api.AbstractObjectAssert;
import org.assertj.core.api.AbstractStringAssert; import org.assertj.core.api.AbstractStringAssert;
import org.assertj.core.api.AssertFactory;
import org.assertj.core.api.Assertions; import org.assertj.core.api.Assertions;
import org.assertj.core.api.InstanceOfAssertFactories;
import org.assertj.core.api.ObjectArrayAssert; import org.assertj.core.api.ObjectArrayAssert;
import org.assertj.core.error.BasicErrorMessageFactory; import org.assertj.core.error.BasicErrorMessageFactory;
import org.assertj.core.internal.Failures; import org.assertj.core.internal.Failures;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.core.ResolvableType; import org.springframework.core.ResolvableType;
import org.springframework.http.HttpInputMessage; import org.springframework.http.HttpInputMessage;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
@ -152,16 +154,23 @@ public abstract class AbstractJsonValueAssert<SELF extends AbstractJsonValueAsse
} }
/** /**
* Verify that the actual value can be converted to an instance of the * Verify that the actual value can be converted to an instance of the type
* given {@code target}, and produce a new {@linkplain AbstractObjectAssert * defined by the given {@link AssertFactory} and return a new Assert narrowed
* assertion} object narrowed to that type. * to that type.
* @param target the {@linkplain ParameterizedTypeReference parameterized * <p>{@link InstanceOfAssertFactories} provides static factories for all the
* type} to convert the actual value to * 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(); isNotNull();
T value = convertToTargetType(target.getType()); return assertFactory.createAssert(this::convertToTargetType);
return Assertions.assertThat(value);
} }
/** /**

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

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

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

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

Loading…
Cancel
Save