Add utilities to help with JSON testing
Add Jackson, Gson and Basic String helper classes that allow AssertJ assertions to be used to test JSON. Fixes gh-5471
This commit is contained in:
@@ -0,0 +1,372 @@
|
||||
/*
|
||||
* Copyright 2012-2016 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
|
||||
*
|
||||
* http://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.boot.test.json;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.Closeable;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.Reader;
|
||||
import java.io.StringReader;
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
import org.assertj.core.api.Assertions;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.ObjectFactory;
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.core.io.ByteArrayResource;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.core.io.FileSystemResource;
|
||||
import org.springframework.core.io.InputStreamResource;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
import org.springframework.util.ReflectionUtils.FieldCallback;
|
||||
|
||||
/**
|
||||
* Base class for AssertJ based JSON marshal testers. Exposes specific Asserts following a
|
||||
* {@code read}, {@code write} or {@code parse} of JSON content. Typically used in
|
||||
* combination with an AssertJ {@link Assertions#assertThat(Object) assertThat} call. For
|
||||
* example: <pre class="code">
|
||||
* public class ExampleObjectJsonTests {
|
||||
*
|
||||
* private AbstractJsonTester<ExampleObject> json = //...
|
||||
*
|
||||
* @Test
|
||||
* public void testWriteJson() {
|
||||
* ExampleObject object = //...
|
||||
* assertThat(json.write(object)).isEqualToJson("expected.json");
|
||||
* assertThat(json.read("expected.json)).isEqualTo(object);
|
||||
* }
|
||||
*
|
||||
* }
|
||||
* </pre> For a complete list of supported assertions see {@link JsonContentAssert} and
|
||||
* {@link ObjectContentAssert}.
|
||||
* <p>
|
||||
* To use this library JSONAssert must be on the test classpath.
|
||||
*
|
||||
* @param <T> The type under test
|
||||
* @author Phillip Webb
|
||||
* @since 1.4.0
|
||||
* @see JsonContentAssert
|
||||
* @see ObjectContentAssert
|
||||
*/
|
||||
public abstract class AbstractJsonMarshalTester<T> {
|
||||
|
||||
private final Class<?> resourceLoadClass;
|
||||
|
||||
private final ResolvableType type;
|
||||
|
||||
/**
|
||||
* Create a new {@link AbstractJsonMarshalTester} instance.
|
||||
* @param resourceLoadClass the source class used when loading relative classpath
|
||||
* resources
|
||||
* @param type the type under test
|
||||
*/
|
||||
public AbstractJsonMarshalTester(Class<?> resourceLoadClass, ResolvableType type) {
|
||||
Assert.notNull(resourceLoadClass, "ResourceLoadClass must not be null");
|
||||
Assert.notNull(type, "Type must not be null");
|
||||
this.resourceLoadClass = resourceLoadClass;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the type under test.
|
||||
* @return the type under test
|
||||
*/
|
||||
protected final ResolvableType getType() {
|
||||
return this.type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return {@link JsonContent} from writing the specific value.
|
||||
* @param value the value to write
|
||||
* @return the {@link JsonContent}
|
||||
* @throws IOException on write error
|
||||
*/
|
||||
public JsonContent<T> write(T value) throws IOException {
|
||||
Assert.notNull(value, "Value must not be null");
|
||||
String json = writeObject(value, this.type);
|
||||
return new JsonContent<T>(this.resourceLoadClass, this.type, json);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the object created from parsing the specific JSON bytes.
|
||||
* @param jsonBytes the source JSON bytes
|
||||
* @return the resulting object
|
||||
* @throws IOException on parse error
|
||||
*/
|
||||
public T parseObject(byte[] jsonBytes) throws IOException {
|
||||
return parse(jsonBytes).getObject();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return {@link ObjectContent} from parsing the specific JSON bytes.
|
||||
* @param jsonBytes the source JSON bytes
|
||||
* @return the {@link ObjectContent}
|
||||
* @throws IOException on parse error
|
||||
*/
|
||||
public ObjectContent<T> parse(byte[] jsonBytes) throws IOException {
|
||||
Assert.notNull(jsonBytes, "JsonBytes must not be null");
|
||||
return read(new ByteArrayResource(jsonBytes));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the object created from parsing the specific JSON String.
|
||||
* @param jsonString the source JSON string
|
||||
* @return the resulting object
|
||||
* @throws IOException on parse error
|
||||
*/
|
||||
public T parseObject(String jsonString) throws IOException {
|
||||
return parse(jsonString).getObject();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return {@link ObjectContent} from parsing the specific JSON String.
|
||||
* @param jsonString the source JSON string
|
||||
* @return the {@link ObjectContent}
|
||||
* @throws IOException on parse error
|
||||
*/
|
||||
public ObjectContent<T> parse(String jsonString) throws IOException {
|
||||
Assert.notNull(jsonString, "JsonString must not be null");
|
||||
return read(new StringReader(jsonString));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the object created from reading from the specified classpath resource.
|
||||
* @param resourcePath the source resource path. May be a full path or a path relative
|
||||
* to the {@code resourceLoadClass} passed to the constructor
|
||||
* @return the resulting object
|
||||
* @throws IOException on read error
|
||||
*/
|
||||
public T readObject(String resourcePath) throws IOException {
|
||||
return read(resourcePath).getObject();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return {@link ObjectContent} from reading from the specified classpath resource.
|
||||
* @param resourcePath the source resource path. May be a full path or a path relative
|
||||
* to the {@code resourceLoadClass} passed to the constructor
|
||||
* @return the {@link ObjectContent}
|
||||
* @throws IOException on read error
|
||||
*/
|
||||
public ObjectContent<T> read(String resourcePath) throws IOException {
|
||||
Assert.notNull(resourcePath, "ResourcePath must not be null");
|
||||
return read(new ClassPathResource(resourcePath, this.resourceLoadClass));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the object created from reading from the specified file.
|
||||
* @param file the source file
|
||||
* @return the resulting object
|
||||
* @throws IOException on read error
|
||||
*/
|
||||
public T readObject(File file) throws IOException {
|
||||
return read(file).getObject();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return {@link ObjectContent} from reading from the specified file.
|
||||
* @param file the source file
|
||||
* @return the {@link ObjectContent}
|
||||
* @throws IOException on read error
|
||||
*/
|
||||
public ObjectContent<T> read(File file) throws IOException {
|
||||
Assert.notNull(file, "File must not be null");
|
||||
return read(new FileSystemResource(file));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the object created from reading from the specified input stream.
|
||||
* @param inputStream the source input stream
|
||||
* @return the resulting object
|
||||
* @throws IOException on read error
|
||||
*/
|
||||
public T readObject(InputStream inputStream) throws IOException {
|
||||
return read(inputStream).getObject();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return {@link ObjectContent} from reading from the specified input stream.
|
||||
* @param inputStream the source input stream
|
||||
* @return the {@link ObjectContent}
|
||||
* @throws IOException on read error
|
||||
*/
|
||||
public ObjectContent<T> read(InputStream inputStream) throws IOException {
|
||||
Assert.notNull(inputStream, "InputStream must not be null");
|
||||
return read(new InputStreamResource(inputStream));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the object created from reading from the specified resource.
|
||||
* @param resource the source resource
|
||||
* @return the resulting object
|
||||
* @throws IOException on read error
|
||||
*/
|
||||
public T readObject(Resource resource) throws IOException {
|
||||
return read(resource).getObject();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return {@link ObjectContent} from reading from the specified resource.
|
||||
* @param resource the source resource
|
||||
* @return the {@link ObjectContent}
|
||||
* @throws IOException on read error
|
||||
*/
|
||||
public ObjectContent<T> read(Resource resource) throws IOException {
|
||||
Assert.notNull(resource, "Resource must not be null");
|
||||
InputStream inputStream = resource.getInputStream();
|
||||
T object = readObject(inputStream, this.type);
|
||||
closeQuietly(inputStream);
|
||||
return new ObjectContent<T>(this.type, object);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the object created from reading from the specified reader.
|
||||
* @param reader the source reader
|
||||
* @return the resulting object
|
||||
* @throws IOException on read error
|
||||
*/
|
||||
public T readObject(Reader reader) throws IOException {
|
||||
return read(reader).getObject();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return {@link ObjectContent} from reading from the specified reader.
|
||||
* @param reader the source reader
|
||||
* @return the {@link ObjectContent}
|
||||
* @throws IOException on read error
|
||||
*/
|
||||
public ObjectContent<T> read(Reader reader) throws IOException {
|
||||
Assert.notNull(reader, "Reader must not be null");
|
||||
T object = readObject(reader, this.type);
|
||||
closeQuietly(reader);
|
||||
return new ObjectContent<T>(this.type, object);
|
||||
}
|
||||
|
||||
private void closeQuietly(Closeable closeable) {
|
||||
try {
|
||||
closeable.close();
|
||||
}
|
||||
catch (IOException ex) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the specified object to a JSON string.
|
||||
* @param value the source value ({@code never null})
|
||||
* @param type the resulting type ({@code never null})
|
||||
* @return the JSON string
|
||||
* @throws IOException on write error
|
||||
*/
|
||||
protected abstract String writeObject(T value, ResolvableType type)
|
||||
throws IOException;
|
||||
|
||||
/**
|
||||
* Read from the specified input stream to create an object of the specified type. The
|
||||
* default implementation delegates to {@link #readObject(Reader, ResolvableType)}
|
||||
* @param inputStream the source input stream ({@code never null})
|
||||
* @param type the resulting type ({@code never null})
|
||||
* @return the resulting object
|
||||
* @throws IOException on read error
|
||||
*/
|
||||
protected T readObject(InputStream inputStream, ResolvableType type)
|
||||
throws IOException {
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
|
||||
return readObject(reader, type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read from the specified reader to create an object of the specified type.
|
||||
* @param reader the source reader ({@code never null})
|
||||
* @param type the resulting type ({@code never null})
|
||||
* @return the resulting object
|
||||
* @throws IOException on read error
|
||||
*/
|
||||
protected abstract T readObject(Reader reader, ResolvableType type)
|
||||
throws IOException;
|
||||
|
||||
/**
|
||||
* Utility class used to support field initialization. Uses by subclasses to support
|
||||
* {@code initFields}.
|
||||
* @param <M> The marshaller type
|
||||
*/
|
||||
protected static abstract class FieldInitializer<M> {
|
||||
|
||||
private final Class<?> testerClass;
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
protected FieldInitializer(
|
||||
Class<? extends AbstractJsonMarshalTester> testerClass) {
|
||||
Assert.notNull(testerClass, "TesterClass must not be null");
|
||||
this.testerClass = testerClass;
|
||||
}
|
||||
|
||||
public void initFields(final Object testInstance, final M marshaller) {
|
||||
Assert.notNull(testInstance, "TestInstance must not be null");
|
||||
Assert.notNull(marshaller, "Marshaller must not be null");
|
||||
initFields(testInstance, new ObjectFactory<M>() {
|
||||
|
||||
@Override
|
||||
public M getObject() throws BeansException {
|
||||
return marshaller;
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
public void initFields(final Object testInstance,
|
||||
final ObjectFactory<M> marshaller) {
|
||||
Assert.notNull(testInstance, "TestInstance must not be null");
|
||||
Assert.notNull(marshaller, "Marshaller must not be null");
|
||||
ReflectionUtils.doWithFields(testInstance.getClass(), new FieldCallback() {
|
||||
|
||||
@Override
|
||||
public void doWith(Field field)
|
||||
throws IllegalArgumentException, IllegalAccessException {
|
||||
doWithField(field, testInstance, marshaller);
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
protected void doWithField(Field field, Object test,
|
||||
ObjectFactory<M> marshaller) {
|
||||
if (this.testerClass.isAssignableFrom(field.getType())) {
|
||||
ReflectionUtils.makeAccessible(field);
|
||||
Object existingValue = ReflectionUtils.getField(field, test);
|
||||
if (existingValue == null) {
|
||||
setupField(field, test, marshaller);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void setupField(Field field, Object test, ObjectFactory<M> marshaller) {
|
||||
ResolvableType type = ResolvableType.forField(field).getGeneric();
|
||||
ReflectionUtils.setField(field, test,
|
||||
createTester(test.getClass(), type, marshaller.getObject()));
|
||||
}
|
||||
|
||||
protected abstract AbstractJsonMarshalTester<Object> createTester(
|
||||
Class<?> resourceLoadClass, ResolvableType type, M marshaller);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
* Copyright 2012-2016 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
|
||||
*
|
||||
* http://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.boot.test.json;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* AssertJ based JSON tester that works with basic JSON strings. Allows testing of JSON
|
||||
* payloads created from some any source, for example:<pre class="code">
|
||||
* public class ExampleObjectJsonTests {
|
||||
*
|
||||
* private BasicJsonTester = new BasicJsonTester(getClass());
|
||||
*
|
||||
* @Test
|
||||
* public void testWriteJson() {
|
||||
* assertThat(json.from("example.json")).extractingJsonPathStringValue("@.name")
|
||||
.isEqualTo("Spring");
|
||||
* }
|
||||
*
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* See {@link AbstractJsonMarshalTester} for more details.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @since 1.4.0
|
||||
*/
|
||||
public class BasicJsonTester {
|
||||
|
||||
private final JsonLoader loader;
|
||||
|
||||
/**
|
||||
* Create a new {@link BasicJsonTester} instance.
|
||||
* @param resourceLoadClass the source class used to load resources
|
||||
*/
|
||||
public BasicJsonTester(Class<?> resourceLoadClass) {
|
||||
Assert.notNull(resourceLoadClass, "ResourceLoadClass must not be null");
|
||||
this.loader = new JsonLoader(resourceLoadClass);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create JSON content from the specified String source. The source can contain the
|
||||
* JSON itself or, if it ends with {@code .json}, the name of a resource to be loaded
|
||||
* using {@code resourceLoadClass}.
|
||||
* @param source JSON content or a {@code .json} resource name
|
||||
* @return the JSON content
|
||||
* @throws IOException on load error
|
||||
*/
|
||||
public JsonContent<Object> from(CharSequence source) throws IOException {
|
||||
return getJsonContent(this.loader.getJson(source));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create JSON content from the specified resource path.
|
||||
* @param path the path of the resource to load
|
||||
* @param resourceLoadClass the classloader used load the resource
|
||||
* @return the JSON content
|
||||
* @throws IOException on load error
|
||||
*/
|
||||
public JsonContent<Object> from(String path, Class<?> resourceLoadClass)
|
||||
throws IOException {
|
||||
return getJsonContent(this.loader.getJson(path, resourceLoadClass));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create JSON content from the specified JSON bytes.
|
||||
* @param source the bytes of JSON
|
||||
* @return the JSON content
|
||||
* @throws IOException on load error
|
||||
*/
|
||||
public JsonContent<Object> from(byte[] source) throws IOException {
|
||||
return getJsonContent(this.loader.getJson(source));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create JSON content from the specified JSON file.
|
||||
* @param source the file containing JSON
|
||||
* @return the JSON content
|
||||
* @throws IOException on load error
|
||||
*/
|
||||
public JsonContent<Object> from(File source) throws IOException {
|
||||
return getJsonContent(this.loader.getJson(source));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create JSON content from the specified JSON input stream.
|
||||
* @param source the input stream containing JSON
|
||||
* @return the JSON content
|
||||
* @throws IOException on load error
|
||||
*/
|
||||
public JsonContent<Object> from(InputStream source) throws IOException {
|
||||
return getJsonContent(this.loader.getJson(source));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create JSON content from the specified JSON resource.
|
||||
* @param source the resource containing JSON
|
||||
* @return the JSON content
|
||||
* @throws IOException on load error
|
||||
*/
|
||||
public JsonContent<Object> from(Resource source) throws IOException {
|
||||
return getJsonContent(this.loader.getJson(source));
|
||||
}
|
||||
|
||||
private JsonContent<Object> getJsonContent(String json) {
|
||||
return new JsonContent<Object>(this.loader.getResourceLoadClass(), null, json);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
* Copyright 2012-2016 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
|
||||
*
|
||||
* http://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.boot.test.json;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Reader;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
|
||||
import org.springframework.beans.factory.ObjectFactory;
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* AssertJ based JSON tester backed by Gson. Usually instantiated via
|
||||
* {@link #initFields(Object, Gson)}, for example: <pre class="code">
|
||||
* public class ExampleObjectJsonTests {
|
||||
*
|
||||
* private GsonTester<ExampleObject> json;
|
||||
*
|
||||
* @Before
|
||||
* public void setup() {
|
||||
* Gson gson = new GsonBuilder().create();
|
||||
* GsonTester.initFields(this, gson);
|
||||
* }
|
||||
*
|
||||
* @Test
|
||||
* public void testWriteJson() {
|
||||
* ExampleObject object = //...
|
||||
* assertThat(json.write(object)).isEqualToJson("expected.json");
|
||||
* }
|
||||
*
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* See {@link AbstractJsonMarshalTester} for more details.
|
||||
*
|
||||
* @param <T> The type under test
|
||||
* @author Phillip Webb
|
||||
* @since 1.4.0
|
||||
*/
|
||||
public class GsonTester<T> extends AbstractJsonMarshalTester<T> {
|
||||
|
||||
private final Gson gson;
|
||||
|
||||
/**
|
||||
* Create a new {@link GsonTester} instance.
|
||||
* @param resourceLoadClass the source class used to load resources
|
||||
* @param type the type under test
|
||||
* @param gson the Gson instance
|
||||
* @see #initFields(Object, Gson)
|
||||
*/
|
||||
public GsonTester(Class<?> resourceLoadClass, ResolvableType type, Gson gson) {
|
||||
super(resourceLoadClass, type);
|
||||
Assert.notNull(gson, "Gson must not be null");
|
||||
this.gson = gson;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String writeObject(T value, ResolvableType type) throws IOException {
|
||||
return this.gson.toJson(value, type.getType());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected T readObject(Reader reader, ResolvableType type) throws IOException {
|
||||
return this.gson.fromJson(reader, type.getType());
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility method to initialize {@link JacksonTester} fields. See {@link JacksonTester
|
||||
* class-level documentation} for example usage.
|
||||
* @param testInstance the test instance
|
||||
* @param gson the Gson instance
|
||||
*/
|
||||
public static void initFields(Object testInstance, Gson gson) {
|
||||
new GsonFieldInitializer().initFields(testInstance, gson);
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility method to initialize {@link JacksonTester} fields. See {@link JacksonTester
|
||||
* class-level documentation} for example usage.
|
||||
* @param testInstance the test instance
|
||||
* @param gson an object factory to create the Gson instance
|
||||
*/
|
||||
public static void initFields(Object testInstance, ObjectFactory<Gson> gson) {
|
||||
new GsonFieldInitializer().initFields(testInstance, gson);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link JsonTesterFieldInitializer} for Gson.
|
||||
*/
|
||||
private static class GsonFieldInitializer extends FieldInitializer<Gson> {
|
||||
|
||||
protected GsonFieldInitializer() {
|
||||
super(GsonTester.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AbstractJsonMarshalTester<Object> createTester(
|
||||
Class<?> resourceLoadClass, ResolvableType type, Gson marshaller) {
|
||||
return new GsonTester<Object>(resourceLoadClass, type, marshaller);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
/*
|
||||
* Copyright 2012-2016 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
|
||||
*
|
||||
* http://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.boot.test.json;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.Reader;
|
||||
|
||||
import com.fasterxml.jackson.databind.JavaType;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
import org.springframework.beans.factory.ObjectFactory;
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* AssertJ based JSON tester backed by Jackson. Usually instantiated via
|
||||
* {@link #initFields(Object, ObjectMapper)}, for example: <pre class="code">
|
||||
* public class ExampleObjectJsonTests {
|
||||
*
|
||||
* private JacksonTester<ExampleObject> json;
|
||||
*
|
||||
* @Before
|
||||
* public void setup() {
|
||||
* ObjectMapper objectMapper = new ObjectMapper();
|
||||
* JacksonTester.initFields(this, objectMapper);
|
||||
* }
|
||||
*
|
||||
* @Test
|
||||
* public void testWriteJson() {
|
||||
* ExampleObject object = //...
|
||||
* assertThat(json.write(object)).isEqualToJson("expected.json");
|
||||
* }
|
||||
*
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* See {@link AbstractJsonMarshalTester} for more details.
|
||||
*
|
||||
* @param <T> The type under test
|
||||
* @author Phillip Webb
|
||||
* @since 1.4.0
|
||||
*/
|
||||
public class JacksonTester<T> extends AbstractJsonMarshalTester<T> {
|
||||
|
||||
private final ObjectMapper objectMapper;
|
||||
|
||||
/**
|
||||
* Create a new {@link JacksonTester} instance.
|
||||
* @param resourceLoadClass the source class used to load resources
|
||||
* @param type the type under test
|
||||
* @param objectMapper the Jackson object mapper
|
||||
*/
|
||||
public JacksonTester(Class<?> resourceLoadClass, ResolvableType type,
|
||||
ObjectMapper objectMapper) {
|
||||
super(resourceLoadClass, type);
|
||||
Assert.notNull(objectMapper, "ObjectMapper must not be null");
|
||||
this.objectMapper = objectMapper;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected T readObject(InputStream inputStream, ResolvableType type)
|
||||
throws IOException {
|
||||
return this.objectMapper.readValue(inputStream, getType(type));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected T readObject(Reader reader, ResolvableType type) throws IOException {
|
||||
return this.objectMapper.readerFor(getType(type)).readValue(reader);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String writeObject(T value, ResolvableType type) throws IOException {
|
||||
return this.objectMapper.writerFor(getType(type)).writeValueAsString(value);
|
||||
}
|
||||
|
||||
private JavaType getType(ResolvableType type) {
|
||||
return this.objectMapper.constructType(type.getType());
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility method to initialize {@link JacksonTester} fields. See {@link JacksonTester
|
||||
* class-level documentation} for example usage.
|
||||
* @param testInstance the test instance
|
||||
* @param objectMapper the object mapper
|
||||
* @see #initFields(Object, ObjectMapper)
|
||||
*/
|
||||
public static void initFields(Object testInstance, ObjectMapper objectMapper) {
|
||||
new JacksonFieldInitializer().initFields(testInstance, objectMapper);
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility method to initialize {@link JacksonTester} fields. See {@link JacksonTester
|
||||
* class-level documentation} for example usage.
|
||||
* @param testInstance the test instance
|
||||
* @param objectMapperFactory a factory to create the object mapper
|
||||
* @see #initFields(Object, ObjectMapper)
|
||||
*/
|
||||
public static void initFields(Object testInstance,
|
||||
ObjectFactory<ObjectMapper> objectMapperFactory) {
|
||||
new JacksonFieldInitializer().initFields(testInstance, objectMapperFactory);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link JsonTesterFieldInitializer} for Jackson.
|
||||
*/
|
||||
private static class JacksonFieldInitializer extends FieldInitializer<ObjectMapper> {
|
||||
|
||||
protected JacksonFieldInitializer() {
|
||||
super(JacksonTester.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AbstractJsonMarshalTester<Object> createTester(
|
||||
Class<?> resourceLoadClass, ResolvableType type,
|
||||
ObjectMapper marshaller) {
|
||||
return new JacksonTester<Object>(resourceLoadClass, type, marshaller);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright 2012-2016 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
|
||||
*
|
||||
* http://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.boot.test.json;
|
||||
|
||||
import org.assertj.core.api.AssertProvider;
|
||||
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* JSON content created usually from a JSON tester. Generally used only to
|
||||
* {@link AssertProvider provide} {@link JsonContentAssert} to AssertJ {@code assertThat}
|
||||
* calls.
|
||||
*
|
||||
* @param <T> The source type that created the content
|
||||
* @author Phillip Webb
|
||||
* @since 1.4.0
|
||||
*/
|
||||
public final class JsonContent<T> implements AssertProvider<JsonContentAssert> {
|
||||
|
||||
private final Class<?> resourceLoadClass;
|
||||
|
||||
private final ResolvableType type;
|
||||
|
||||
private final String json;
|
||||
|
||||
/**
|
||||
* Create a new {@link JsonContent} instance.
|
||||
* @param resourceLoadClass the source class used to load resources
|
||||
* @param type the type under test (or {@code null} if not known)
|
||||
* @param json the actual JSON content
|
||||
*/
|
||||
public JsonContent(Class<?> resourceLoadClass, ResolvableType type, String json) {
|
||||
Assert.notNull(resourceLoadClass, "ResourceLoadClass must not be null");
|
||||
Assert.notNull(json, "JSON must not be null");
|
||||
this.resourceLoadClass = resourceLoadClass;
|
||||
this.type = type;
|
||||
this.json = json;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonContentAssert assertThat() {
|
||||
return new JsonContentAssert(this.resourceLoadClass, this.json);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the actual JSON content string.
|
||||
* @return the JSON content
|
||||
*/
|
||||
public String getJson() {
|
||||
return this.json;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "JsonContent " + this.json
|
||||
+ (this.type == null ? "" : " created from " + this.type);
|
||||
}
|
||||
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright 2012-2016 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
|
||||
*
|
||||
* http://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.boot.test.json;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.util.FileCopyUtils;
|
||||
|
||||
/**
|
||||
* Internal helper used to load JSON from various sources.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
class JsonLoader {
|
||||
|
||||
private final Class<?> resourceLoadClass;
|
||||
|
||||
JsonLoader(Class<?> resourceLoadClass) {
|
||||
this.resourceLoadClass = resourceLoadClass;
|
||||
}
|
||||
|
||||
public Class<?> getResourceLoadClass() {
|
||||
return this.resourceLoadClass;
|
||||
}
|
||||
|
||||
public String getJson(CharSequence source) throws IOException {
|
||||
if (source == null) {
|
||||
return null;
|
||||
}
|
||||
if (source.toString().endsWith(".json")) {
|
||||
return getJson(
|
||||
new ClassPathResource(source.toString(), this.resourceLoadClass));
|
||||
}
|
||||
return source.toString();
|
||||
}
|
||||
|
||||
public String getJson(String path, Class<?> resourceLoadClass) throws IOException {
|
||||
return getJson(new ClassPathResource(path, resourceLoadClass));
|
||||
}
|
||||
|
||||
public String getJson(byte[] source) throws IOException {
|
||||
return getJson(new ByteArrayInputStream(source));
|
||||
}
|
||||
|
||||
public String getJson(File source) throws IOException {
|
||||
return getJson(new FileInputStream(source));
|
||||
}
|
||||
|
||||
public String getJson(Resource source) throws IOException {
|
||||
return getJson(source.getInputStream());
|
||||
}
|
||||
|
||||
public String getJson(InputStream source) throws IOException {
|
||||
return FileCopyUtils.copyToString(new InputStreamReader(source));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright 2012-2016 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
|
||||
*
|
||||
* http://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.boot.test.json;
|
||||
|
||||
import org.assertj.core.api.AssertProvider;
|
||||
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Object content usually created from {@link AbstractJsonMarshalTester}.Generally used
|
||||
* only to {@link AssertProvider provide} {@link ObjectContentAssert} to AssertJ
|
||||
* {@code assertThat} calls.
|
||||
*
|
||||
* @param <T> The content type
|
||||
* @author Phillip Webb
|
||||
* @since 1.4.0
|
||||
*/
|
||||
public final class ObjectContent<T> implements AssertProvider<ObjectContentAssert<T>> {
|
||||
|
||||
private final ResolvableType type;
|
||||
|
||||
private final T object;
|
||||
|
||||
/**
|
||||
* Create a new {@link ObjectContent} instance.
|
||||
* @param type the type under test (or {@code null} if not known)
|
||||
* @param object the actual object content
|
||||
*/
|
||||
public ObjectContent(ResolvableType type, T object) {
|
||||
Assert.notNull(object, "Object must not be null");
|
||||
this.type = type;
|
||||
this.object = object;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ObjectContentAssert<T> assertThat() {
|
||||
return new ObjectContentAssert<T>(this.object);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the actual object content.
|
||||
* @return the object content
|
||||
*/
|
||||
public T getObject() {
|
||||
return this.object;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ObjectContent " + this.object
|
||||
+ (this.type == null ? "" : " created from " + this.type);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright 2012-2016 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
|
||||
*
|
||||
* http://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.boot.test.json;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.assertj.core.api.AbstractMapAssert;
|
||||
import org.assertj.core.api.AbstractObjectArrayAssert;
|
||||
import org.assertj.core.api.AbstractObjectAssert;
|
||||
import org.assertj.core.api.Assert;
|
||||
import org.assertj.core.api.Assertions;
|
||||
import org.assertj.core.internal.Objects;
|
||||
|
||||
/**
|
||||
* AssertJ {@link Assert} for {@link JsonContent}.
|
||||
*
|
||||
* @param <A> The actual type
|
||||
* @author Phillip Webb
|
||||
* @since 1.4.0
|
||||
*/
|
||||
public class ObjectContentAssert<A>
|
||||
extends AbstractObjectAssert<ObjectContentAssert<A>, A> {
|
||||
|
||||
protected ObjectContentAssert(A actual) {
|
||||
super(actual, ObjectContentAssert.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that the actual value is an array, and returns an array assertion, to
|
||||
* allow chaining of array-specific assertions from this call.
|
||||
* @return a list assertion object
|
||||
*/
|
||||
public AbstractObjectArrayAssert<?, Object> asArray() {
|
||||
Objects.instance().assertIsInstanceOf(this.info, this.actual, Object[].class);
|
||||
return Assertions.assertThat((Object[]) this.actual);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that the actual value is a map, and returns a map assertion, to allow
|
||||
* chaining of list-specific assertions from this call.
|
||||
* @return a list assertion object
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public AbstractMapAssert<?, ?, Object, Object> asMap() {
|
||||
Objects.instance().assertIsInstanceOf(this.info, this.actual, Map.class);
|
||||
return Assertions.assertThat((Map<Object, Object>) this.actual);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright 2012-2016 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
|
||||
*
|
||||
* http://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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Support for testing JSON.
|
||||
*/
|
||||
package org.springframework.boot.test.json;
|
||||
Reference in New Issue
Block a user