count members with jsonpath?

前端 未结 5 960
生来不讨喜
生来不讨喜 2020-12-22 20:42

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

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

{\"foo\": \"oof\", \"ba         


        
相关标签:
5条回答
  • 2020-12-22 21:13

    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
        }
    })
    
    0 讨论(0)
  • 2020-12-22 21:13

    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]

    0 讨论(0)
  • 2020-12-22 21:22

    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.

    0 讨论(0)
  • 2020-12-22 21:33

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

    @Test
    public void givenJson_whenGetLengthWithJsonPath_thenGetLength() {
        String jsonString = "{'username':'jhon.user','email':'jhon@company.com','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':'jhon@company.com','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.

    0 讨论(0)
  • 2020-12-22 21:36

    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)));
    
    0 讨论(0)
提交回复
热议问题