Hamcrest JSON Matchers

I couldn’t find a Hamcrest matcher for JSON that worked how I wanted, so I adapted the JsonAssert library.

This allows you to use dot notation to specify the path to a node in a json string, and use any Hamcrest matcher to check the contents of the string at that node.

For example, given a Json string like:

 {"someThing": {
    "innerThing": {
        "partOne": "abc",
        "partTwo": 123
    }
 }}

 

You could call


assertThat(jsonString,
  hasJsonPath("someThing.innerThing.partOne", equalTo("abc")));

assertThat(jsonString,
  hasJsonPath("someThing.innerThing.partOne", greaterThan(100)));

That’s not massively different to the syntax you get with JsonAssert, but I prefer it. The equivalent with JsonAssert would be


with(jsonString)
  .assertThat("someThing.innerThing.partOne", equalTo("abc"));

which doesn’t seem quite so fluent.

Note that the matcher you use for the value of the required node must be a matcher for the unmarshalled type.

In other words, if the node contains “abc” then a Matcher<String> can be used, and if it contained 123 then a Matcher<Integer> could be used.

 


import static com.jayway.jsonassert.JsonAssert.with;

import org.hamcrest.Description;
import org.hamcrest.Matcher;
import org.hamcrest.TypeSafeMatcher;

public class JsonMatchers {

  public static <T> Matcher<String> hasJsonPath(
    final String jsonPath, final Matcher<T> matches) {

    return new TypeSafeMatcher<String>() {
      @Override
      protected boolean matchesSafely(String json) {
        try {
          with(json).assertThat(jsonPath, matches);
          return true;
        } catch (AssertionError ae) {
          return false;
        } catch (Exception e) {
          return false;
        }
      }

      @Override
      public void describeTo(Description description) {
        description
          .appendText(" JSON object with a value at node ")
          .appendValue(jsonPath)
          .appendText(" that is ")
          .appendDescriptionOf(matches);
      }
    };
  }
}

OK, that’s a bit of a quick hack, and it looks very ugly formatted to fit this page, but it does the job. It gives you easy to read assertions without a load of awkward engineering just to deal with the json, or clumsy string matching that isn’t precise enough and causes tests to be brittle and not expressive.

Hamcrest is cool.

 

PS you’ll need the json-path-assert dependency


<dependency>
<groupId>com.jayway.jsonpath</groupId>
<artifactId>json-path-assert</artifactId>
<version>0.9.1</version>
<scope>test</scope>
</dependency>

Advertisements
Posted in Clean Test Code, Hamcrest
One comment on “Hamcrest JSON Matchers
  1. 어성효 says:

    wow clear !!!
    This is very helpful series of articles. Very nice job

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: