This post shows how you can write JUnit tests to check if an object matches a JSON string. This is important if you are implementing REST services and want to test if your service produces the expected JSON response.
A useful library for comparing JSON objects is JSONassert. First, you have to convert your Java object into a JSON string (using Jackson, for example) and then compare it with your expected JSON string using JSONassert. (You could also convert your Java object into a JSONObject but I find that it's much easier to convert it into a string.)
The following snippet shows how you can compare an object (a List, in this case) against its JSON representation using JSONassert.
import org.skyscreamer.jsonassert.JSONAssert;
import com.fasterxml.jackson.databind.ObjectMapper;
List<String> fruits = Arrays.asList("apple", "banana");
String fruitsJSON = new ObjectMapper().writeValueAsString(fruits);
String expectedFruitsJSON = "[\"apple\", \"banana\"]";
JSONAssert.assertEquals(expectedFruitsJSON, fruitsJSON, true);
In order to make it simpler to write such unit tests, I have written a Hamcrest Matcher called IsEqualJSON for comparing JSON objects. It still uses JSONassert but allows you to express your tests in a more fluent way.
The following code shows how IsEqualJSON is used:
import static org.junit.Assert.*;
import static testutil.IsEqualJSON.*;
assertThat(Arrays.asList("apple", "banana"),
equalToJSON("[\"apple\", \"banana\"]"));
// you can also have your expected JSON read from a file
assertThat(Arrays.asList("apple", "banana"),
equalToJSONInFile("fruits.json"));
Here is the code for IsEqualJSON (also available in my GitHub Repository):
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.*;
import org.hamcrest.*;
import org.skyscreamer.jsonassert.*;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
/**
* A Matcher for comparing JSON.
* Example usage:
* <pre>
* assertThat(new String[] {"foo", "bar"}, equalToJSON("[\"foo\", \"bar\"]"));
* assertThat(new String[] {"foo", "bar"}, equalToJSONInFile("/tmp/foo.json"));
* </pre>
*/
public class IsEqualJSON extends DiagnosingMatcher<Object> {
private final String expectedJSON;
private JSONCompareMode jsonCompareMode;
public IsEqualJSON(final String expectedJSON) {
this.expectedJSON = expectedJSON;
this.jsonCompareMode = JSONCompareMode.STRICT;
}
@Override
public void describeTo(final Description description) {
description.appendText(expectedJSON);
}
@Override
protected boolean matches(final Object actual,
final Description mismatchDescription) {
final String actualJSON = toJSONString(actual);
final JSONCompareResult result = JSONCompare.compareJSON(expectedJSON,
actualJSON,
jsonCompareMode);
if (!result.passed()) {
mismatchDescription.appendText(result.getMessage());
}
return result.passed();
}
private static String toJSONString(final Object o) {
try {
return o instanceof String ?
(String) o : new ObjectMapper().writeValueAsString(o);
} catch (final JsonProcessingException e) {
throw new RuntimeException(e);
}
}
private static String getFileContents(final Path path) {
try {
return new String(Files.readAllBytes(path), StandardCharsets.UTF_8);
} catch (final IOException e) {
throw new RuntimeException(e);
}
}
@Factory
public static IsEqualJSON equalToJSON(final String expectedJSON) {
return new IsEqualJSON(expectedJSON);
}
@Factory
public static IsEqualJSON equalToJSONInFile(final Path expectedPath) {
return equalToJSON(getFileContents(expectedPath));
}
@Factory
public static IsEqualJSON equalToJSONInFile(final String expectedFileName) {
return equalToJSONInFile(Paths.get(expectedFileName));
}
}
No comments:
Post a Comment
Note: Only a member of this blog may post a comment.