count members with jsonpath?

JavaSpringTestingJsonpathSpring Test-Mvc

Java Problem Overview


Is it possible to count the number of members using JsonPath?

Using spring mvc test I'm testing a controller that generates

{"foo": "oof", "bar": "rab"}

with

standaloneSetup(new FooController(fooService)).build()
			.perform(get("/something").accept(MediaType.APPLICATION_JSON)).andExpect(status().isOk())
			.andExpect(jsonPath("$.foo").value("oof"))
			.andExpect(jsonPath("$.bar").value("rab"));

I'd like to make sure that no other members are present in the generated json. Hopefully by counting them using jsonPath. Is it possible? Alternate solutions are welcome too.

Java Solutions


Solution 1 - Java

To test size of array: jsonPath("$", hasSize(4))

To count members of object: jsonPath("$.*", hasSize(4))


I.e. to test that API returns an array of 4 items:

accepted value: [1,2,3,4]

mockMvc.perform(get(API_URL))
       .andExpect(jsonPath("$", hasSize(4)));

to test that API returns an object containing 2 members:

accepted value: {"foo": "oof", "bar": "rab"}

mockMvc.perform(get(API_URL))
       .andExpect(jsonPath("$.*", hasSize(2)));

I'm using Hamcrest version 1.3 and Spring Test 3.2.5.RELEASE

hasSize(int) javadoc

Note: You need to include hamcrest-library dependency and import static org.hamcrest.Matchers.*; for hasSize() to work.

Solution 2 - Java

You can also use the methods inside the jsonpath, so instead of

mockMvc.perform(get(API_URL))
   .andExpect(jsonPath("$.*", hasSize(2)));

you can do

mockMvc.perform(get(API_URL))
   .andExpect(jsonPath("$.length()", is(2)));

Solution 3 - Java

We can use JsonPath functions like size() or length(), like this:

@Test
public void givenJson_whenGetLengthWithJsonPath_thenGetLength() {
    String jsonString = "{'username':'jhon.user','email':'[email protected]','age':'28'}";

    int length = JsonPath
        .parse(jsonString)
        .read("$.length()");

    assertThat(length).isEqualTo(3);
}

Or simply parsing to net.minidev.json.JSONObject and get the size:

@Test
public void givenJson_whenParseObject_thenGetSize() {
    String jsonString = "{'username':'jhon.user','email':'[email protected]','age':'28'}";

    JSONObject jsonObject = (JSONObject) JSONValue.parse(jsonString);

    assertThat(jsonObject)
        .size()
        .isEqualTo(3);
}

Indeed, the second approach looks to perform better than the first one. I made a JMH performance test and I get the following results:

| Benchmark                                       | Mode  | Cnt | Score       | Error        | Units |
|-------------------------------------------------|-------|-----|-------------|--------------|-------|
| JsonPathBenchmark.benchmarkJSONObjectParse      | thrpt | 5   | 3241471.044 | ±1718855.506 | ops/s |
| JsonPathBenchmark.benchmarkJsonPathObjectLength | thrpt | 5   | 1680492.243 | ±132492.697  | ops/s |

The example code can be found here.

Solution 4 - Java

Been dealing with this myself today. It doesn't seem like this is implemented in the available assertions. However, there is a method to pass in an org.hamcrest.Matcher object. With that you can do something like the following:

final int count = 4; // expected count

jsonPath("$").value(new BaseMatcher() {
    @Override
    public boolean matches(Object obj) {
        return obj instanceof JSONObject && ((JSONObject) obj).size() == count;
    }

    @Override
    public void describeTo(Description description) {
        // nothing for now
    }
})

Solution 5 - Java

if you don't have com.jayway.jsonassert.JsonAssert on your classpath (which was the case with me), testing in the following way may be a possible workaround:

assertEquals(expectedLength, ((net.minidev.json.JSONArray)parsedContent.read("$")).size());

[note: i assumed that the content of the json is always an array]

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionNA.View Question on Stackoverflow
Solution 1 - JavalopisanView Answer on Stackoverflow
Solution 2 - JavastaletView Answer on Stackoverflow
Solution 3 - JavaJuanMorenoView Answer on Stackoverflow
Solution 4 - JavaBenView Answer on Stackoverflow
Solution 5 - JavaTanvirView Answer on Stackoverflow