Vas*_*kin 2 java spring spring-mvc hamcrest mockmvc
我有一个API端点,当使用GET调用该端点时,将在体内返回一个JSON对象数组,如下所示:
[
{"id": "321", "created": "2019-03-01", "updated": "2019-03-15"},
{"id": "123", "created": "2019-03-02", "updated": "2019-03-16"}
]
Run Code Online (Sandbox Code Playgroud)
我想用Spring MockMvc测试用例检查主体。该语句当前如下所示:
mockMvc.perform(get("/myapi/v1/goodstuff").
andExpect(status().isOk()).
andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8)).
andExpect(jsonPath("$.*", isA(ArrayList.class))).
andExpect(jsonPath("$.*", hasSize(2))).
andExpect(jsonPath("$[0].id", is("321"))).
andExpect(jsonPath("$[0].created", is("2019-03-01"))).
andExpect(jsonPath("$[0].updated*", is("2019-03-15"))).
andExpect(jsonPath("$[1].id", is("1232"))).
andExpect(jsonPath("$[1].created", is("2019-03-02"))).
andExpect(jsonPath("$[1].updated*", is("2019-03-16")));
Run Code Online (Sandbox Code Playgroud)
但是,我的API的实现不能保证返回数组中JSON对象的顺序。如果这是一个字符串数组,我可以通过通过生成的匹配器来解决org.hamcrest.collection.IsIterableContainingInAnyOrder<T>.containsInAnyOrder。但是我在他们的文档中看不到适合我的情况的匹配器,也没有在Spring文档中的jsonPath方法描述中找到任何线索
通过快速搜索,我也没有找到与我在SO上的情况有关的任何东西,除了上面描述的字符串情况之外。当然,我可以将JSON对象转换为字符串。
但是我想知道,我是否可以为一个JSON对象列表解决此问题,将每个对象的每个字段一一比较(就像上面的代码片段所示),但是忽略了对象在集合中的顺序?
更新:Zgurskyi 提出了一个解决方案,可以帮助我简化原始示例。但是,在一个实际的实际示例中,还有2个输入:
is,例如:(更接近我的原始代码)
mockMvc.perform(get("/myapi/v1/greatstuff").
andExpect(status().isOk()).
andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8)).
andExpect(jsonPath("$.*", isA(ArrayList.class))).
andExpect(jsonPath("$.*", hasSize(2))).
andExpect(jsonPath("$[0].id", is("321"))).
andExpect(jsonPath("$[0].did", anything())).
andExpect(jsonPath("$[0].createdTs", startsWith("2019-03-01"))).
andExpect(jsonPath("$[0].updatedTs", startsWith("2019-03-15"))).
andExpect(jsonPath("$[0].name", equalToIgnoringCase("wat"))).
andExpect(jsonPath("$[0].stringValues", containsInAnyOrder("a","b","c"))).
andExpect(jsonPath("$[1].id", is("1232"))).
andExpect(jsonPath("$[1].did", anything())).
andExpect(jsonPath("$[1].createdTs", startsWith("2019-03-01"))).
andExpect(jsonPath("$[1].updatedTs", startsWith("2019-03-15"))).
andExpect(jsonPath("$[1].name", equalToIgnoringCase("taw"))).
andExpect(jsonPath("$[1].stringValues", containsInAnyOrder("d","e","f"))).
andReturn();
Run Code Online (Sandbox Code Playgroud)
到目前为止,似乎没有什么比实现自己的matcher类更好的了。
或者...可以吗?
小智 9
此外,还有另一种方法可以使用 MockMvcResultMatchers 来断言 json,而无需严格遵守顺序
.andExpect(MockMvcResultMatchers.content().json(<json-here>, false))
Run Code Online (Sandbox Code Playgroud)
通过设置strict=false,可以进行筛选搜索。
您可以断言列表项字段而忽略顺序:
.andExpect(jsonPath("$[*].id", containsInAnyOrder("321", "123")))
.andExpect(jsonPath("$[*].created", containsInAnyOrder("2019-03-01", "2019-03-02")))
.andExpect(jsonPath("$[*].updated", containsInAnyOrder("2019-03-15", "2019-03-16")))
Run Code Online (Sandbox Code Playgroud)
另一种方法是检查是否存在特定的列表项作为响应:
.andExpect(jsonPath("$.[?(@.id == 123 && @.created == \"2019-03-02\" && @.updated == \"2019-03-16\")]").exists())
.andExpect(jsonPath("$.[?(@.id == 321 && @.created == \"2019-03-01\" && @.updated == \"2019-03-15\")]").exists())
Run Code Online (Sandbox Code Playgroud)