使用 JsonPath 和 Hamcrest Matchers 匹配字符串列表的更好方法

pdc*_*pdc 5 java hamcrest jsonpath

我正在使用 JsonPath 来测试 API 的 REST 端点。我的测试用例看起来像这样。

首先我创建新对象

class Item {         
    String name;
    int id;
    List<String> places;
}
String name = "Randomname" + new Random().nextLong();
JSONObject obj = new Item(name, 3, Arrays.asList("Rome3", "London3", "Paris3"));
post("/items").content(obj);
Run Code Online (Sandbox Code Playgroud)

然后我得到所有项目的列表,并检查我刚刚创建的项目是否在列表中。

    mockMvc.perform(get("/api/v1/test"))
            .andExpect(jsonPath("$.data[*].name", hasItems("item 1", "item 2")))      // Fine
            .andExpect(jsonPath("$.data[?(@.id == 1)].name", contains("item 1")))
            .andExpect(jsonPath("$.data[?(@.id == 1)].places", contains(contains("Rome1", "London1", "Paris1"))))
            .andReturn();
Run Code Online (Sandbox Code Playgroud)

这可行,但我认为我做得不对,因为我有一个嵌套的contains(contains()). (我已将完整的 JSON 响应放在本文末尾。)

问题是因为 JsonPath 表达式返回一个列表,所以我需要使用列表匹配器。例如,不要写这个

jsonPath("$.data[?(@.id == 1)].name", is("item 1"))
Run Code Online (Sandbox Code Playgroud)

我需要这样写

jsonPath("$.data[?(@.id == 1)].name", contains("item 1"))
Run Code Online (Sandbox Code Playgroud)

因为 JsonPath 表达式将返回一个包含一个元素的 JSON 列表

[
    "item 1"
]
Run Code Online (Sandbox Code Playgroud)

这还不错,但是对于列表来说情况会更糟,例如尝试检查我的变量位置中的字符串列表是否包含我想要的内容。返回的 JSON 是列表的列表,因此这个 JsonPath 表达式

jsonPath("$.data[?(@.id == 1)].places"
Run Code Online (Sandbox Code Playgroud)

将返回这个

        [ 
            [
                "Rome2",
                "London3",
                "Paris3"
            ]
         ]
Run Code Online (Sandbox Code Playgroud)

所以它需要一个嵌套的 hasItems

jsonPath("$.data[?(@.id == 1)].places", hasItems(hasItems("Rome1", "London1")))
Run Code Online (Sandbox Code Playgroud)

这确实有效,但这样做只会让我感觉我没有正确地做这件事,而且我错过了一些东西。

所以我的问题是,处理检查/匹配列表列表的适当方法是什么?

是否有更好的方法来验证端点返回的 JSON?