如何使用 jsonpath 计算成员?

是否可以计算使用 JsonPath 的成员数?

使用 弹簧 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 来计算它们。有可能吗?我们也欢迎其他解决方案。

105455 次浏览

我今天一直在处理这件事。在可用断言中似乎没有实现这一点。但是,有一个方法可以传入 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
}
})

测试 数组: jsonPath("$", hasSize(4))的大小

计算 对象: jsonPath("$.*", hasSize(4))的成员


例如,测试 API 返回4个项目的 数组:

接受价值: [1,2,3,4]

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

测试 API 返回一个包含2个成员的 对象:

接受价值: {"foo": "oof", "bar": "rab"}

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

我使用的是 Hamcrest 版本1.3和 Spring Test 3.2.5

HasSize javadoc

注: 您需要包含 hamcrest-library 依赖项和用于 hasSize ()的 import static org.hamcrest.Matchers.*;才能工作。

如果您的类路径上没有 com.jayway.jsonassert.JsonAssert(我就是这种情况) ,以下方式测试可能是一种可能的解决方案:

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

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

我们可以像 size()length()那样使用 JsonPath 函数,像这样:

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

或者简单地解析为 net.minidev.json.JSONObject并得到大小:

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

事实上,第二种方法看起来比第一种方法表现得更好。我做了一个 JMH 性能测试,得到了以下结果:

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

示例代码可以找到 给你

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

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

你可以的

mockMvc.perform(get(API_URL))
.andExpect(jsonPath("$.length()", is(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)

断言很管用。