Spring MVC 测试中带有过滤器的 JsonPath 表达式

JsonPath expression with filters in Spring MVC test

我有一个控制器 returns 部分列表。这些部分中的每一个都有一个类型。我想测试类型 "JOB" 的部分是否有一个字段 "functions",大小为 3.

这是我的代码:

mockMvc.perform(get(url)
        .contentType(MediaTypes.HAL_JSON)
        .accept(MediaTypes.HAL_JSON))
        .andDo(print())
        .andExpect(status().isOk())
        .andExpect(jsonPath("$._embedded.content", 
                hasSize(equalTo(2))))
        .andExpect(jsonPath("$._embedded.content[?(@.type=='JOB')].functions", 
                hasSize(equalTo(3))));

控制器返回的JSON(为便于阅读而简化):

{
   "_embedded":{
      "content":[
         {
            "subsections":null,
            "type":"PROFILE",
            "createdDate":null,
            "lastModifiedDate":null
         },
         {
            "functions":[
               {
                  "rank":845131,
                  "function":"9IXZT"
               },
               {
                  "rank":82701,
                  "function":"T91WX"
               },
               {
                  "rank":98686,
                  "function":"PA7NA"
               }
            ],
            "type":"JOB",
            "createdDate":null,
            "lastModifiedDate":null
         }
      ]
   }
}

我用 this tool 和那个 JSON 测试了表达式并且工作正常,但是当 运行 测试时我得到这个断言错误:

java.lang.AssertionError: JSON path "$._embedded.content[?(@.type=='JOB')].functions"
Expected: a collection with size <3>
    but: collection size was <1>
        at org.hamcrest.MatcherAssert.assertThat(MatcherAssert.java:20)
        at org.springframework.test.util.JsonPathExpectationsHelper.assertValue(JsonPathExpectationsHelper.java:74)
        at org.springframework.test.web.servlet.result.JsonPathResultMatchers.match(JsonPathResultMatchers.java:86)
        at org.springframework.test.web.servlet.MockMvc.andExpect(MockMvc.java:171)
        ...

在表达式末尾添加 .* 解决了问题,所以现在看起来像这样:

$._embedded.content[?(@.type=='JOB')].functions.*

我不明白为什么示例中的第一个表达式有效,但我必须将 .* 添加到第二个表达式。如果有人知道,请解释一下。

添加 .* 时有所不同。当我在 JSONPath Expression Tester 处填写你的数据时 我得到一个细微但重要的区别:

案例一

$._embedded.content[?(@.type=='JOB')].functions 产量

[
   [
      {
         "rank":845131,
         "function":"9IXZT"
      },
      {
         "rank":82701,
         "function":"T91WX"
      },
      {
         "rank":98686,
         "function":"PA7NA"
      }
   ]
]

案例二

$._embedded.content[?(@.type=='JOB')].functions.*产量

[
   {
      "rank":845131,
      "function":"9IXZT"
   },
   {
      "rank":82701,
      "function":"T91WX"
   },
   {
      "rank":98686,
      "function":"PA7NA"
   }
]

因此对于情况 1,当您采用根节点(它是一个数组)时,您有 一个元素 作为直接子元素:包含三个对象的数组。因此,断言找到了一个大小为 1 的数组(集合)。 对于情况 2,您的数组根节点 包含三个对象 导致集合计数为三个。

也许其他实现方式并非如此。在这个例子中,我使用了 JSONPath 0.3.4Flow Communications 下的实现。


functions后的.将结果的根层级设置为本元素而*表示取本根下的所有元素 .

我没有足够的信心来解释 $._embedded.content[?(@.type=='JOB')].functions 背后的确切行为。不过我觉得跟滤镜有关系?(@.type=='JOB')

https://github.com/json-path/JsonPath#what-is-returned-when