可以使用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 对它们进行计数。是否可以?也欢迎替代解决方案。
测试数组的大小:
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
注意: 您需要包含 hamcrest-library 依赖项和
import static org.hamcrest.Matchers.*;
才能让 hasSize() 工作。
您还可以使用 jsonpath 内的方法,因此代替
mockMvc.perform(get(API_URL))
.andExpect(jsonPath("$.*", hasSize(2)));
你可以做
mockMvc.perform(get(API_URL))
.andExpect(jsonPath("$.length()", is(2)));
我们可以使用 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 |
示例代码可以在这里找到。
今天我自己也在处理这个问题。这似乎没有在可用的断言中实现。不过,有一种方法可以传入
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
}
})
尝试使用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)
断言效果很好。
如果你的类路径上没有
com.jayway.jsonassert.JsonAssert
(我就是这种情况),按以下方式测试可能是一个可能的解决方法:
assertEquals(expectedLength, ((net.minidev.json.JSONArray)parsedContent.read("$")).size());
[注意:我假设json的内容始终是一个数组]
对于那些使用 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))
}
}