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)); } }