如何用jsonpath统计成员数?

问题描述 投票:0回答:7

可以使用JsonPath统计成员数量吗?

使用 Spring MVC 测试我正在测试生成的控制器

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

与:

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

我想确保生成的 json 中不存在其他成员。希望通过使用 jsonPath 对它们进行计数。是否可以?也欢迎替代解决方案。

java spring testing jsonpath spring-test-mvc
7个回答
325
投票

测试数组的大小:

jsonPath("$", hasSize(4))

计算 object 的成员:

jsonPath("$.*", hasSize(4))


即测试 API 返回 4 个项目的array

接受值:

[1,2,3,4]

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

测试 API 返回包含 2 个成员的 object

接受值:

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

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

我正在使用 Hamcrest 版本 1.3 和 Spring Test 3.2.5.RELEASE

hasSize(int) javadoc

注意: 您需要包含 hamcrest-library 依赖项和

import static org.hamcrest.Matchers.*;
才能让 hasSize() 工作。


28
投票

您还可以使用 jsonpath 内的方法,因此代替

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

你可以做

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

12
投票

我们可以使用 JsonPath 函数,例如

size()
length()
,如下所示:

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

或者简单地解析为

net.minidev.json.JSONObject
并获取大小:

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

确实,第二种方法看起来比第一种方法表现更好。我做了 JMH(Java Microbenchmark Harness)性能测试,得到以下结果:

| 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 |

示例代码可以在这里找到。


4
投票

今天我自己也在处理这个问题。这似乎没有在可用的断言中实现。不过,有一种方法可以传入

org.hamcrest.Matcher
对象。这样你就可以执行如下操作:

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

2
投票

尝试使用WebTestClient类似的方法:

webTestClient.get()
    .uri(KEYS_MANAGEMENT_URI)
    .header(
        HttpHeaders.AUTHORIZATION,
        createBearerToken(createJwtClaims(KEYS_AUTHORITY_VIEW))
    )
    .exchange()
    .expectStatus().isOk()
    .expectBody()
    .jsonPath("data").isArray()
    .jsonPath("data.length()").isEqualTo(1)
    .jsonPath("data[0].id").isEqualTo(KEY_ID)

断言效果很好。


0
投票

如果你的类路径上没有

com.jayway.jsonassert.JsonAssert
(我就是这种情况),按以下方式测试可能是一个可能的解决方法:

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

[注意:我假设json的内容始终是一个数组]


0
投票

对于那些使用 Kotlin 的人:org.hamcrest.Matchers#is(T) 会对您有所帮助。 这是一个示例,如果您的根 json 元素是数组:

[
  {
    "someProperty": "someValue"
  },
  {
    "someProperty": "someValue"
  }
]
mvc.get("/your-endpoint")
            .andExpect {
                status { isOk() }
                content { contentType(MediaType.APPLICATION_JSON) }
                content {
                    jsonPath("$.length()", `is`(2))
                }
            }
© www.soinside.com 2019 - 2024. All rights reserved.