Java 请放心:如何使用JSON中的嵌套属性查找元素并验证其他属性

Java 请放心:如何使用JSON中的嵌套属性查找元素并验证其他属性,java,spring-boot,rest-assured,hamcrest,mockmvc,Java,Spring Boot,Rest Assured,Hamcrest,Mockmvc,我在“放心”方面的经验有限。我们有很多测试,我通常可以在google中找到例子,或者失败,但是当我尝试匹配匿名数组中元素的嵌套属性,并上下验证属性(表兄妹?) JSON示例: [ { "id":1, "type":{ "typeId":3, "name":"LPM" }, "status":{ "id":1, "price":1.20,

我在“放心”方面的经验有限。我们有很多测试,我通常可以在google中找到例子,或者失败,但是当我尝试匹配匿名数组中元素的嵌套属性,并上下验证属性(表兄妹?)

JSON示例:

[  
   {  
      "id":1,
      "type":{  
         "typeId":3,
         "name":"LPM"
      },
      "status":{  
         "id":1,
         "price":1.20,
         "source":172,
         "valid":0
      }
   },
   {  
      "id":2,
      "type":{  
         "typeId":2,
         "name":"ST"
      },
      "status":{  
         "id":10,
         "price":1.20,
         "source":172,
         "valid":0
      }
   }
]
我使用的是rest assured,我想在列表中找到
type.name
等于LPM的元素,然后验证该元素的
status.price
status.source
status.id

当我开始验证响应时,数组中只能有一个项目,因此我使用:

response.then()
        .assertThat()
        .body("size", greaterThan(0))
        .body("[0].type.name", equalToIgnoringCase("LPM"))
        .body("[0].status.id", equalTo(statusId))
        .body("[0].status.source", equalTo(sourceId))
        .body("[0].status.price", equalTo(price));
但是,由于数组中可能有多个元素,而且顺序也不能保证,因此无法保证这一点

我已将我的身体检查修改为:

response.then()
        .assertThat()
        .body("size", greaterThan(0))
        .body("type.name", hasItem("LPM"))
        .body("status.id", hasItem(statusId))
        .body("status.source", hasItem(sourceId))
        .body("status.price", hasItem(price));
这足以让测试通过,但这会带来风险,即
类型为.name
的元素的
status.id
status.source
status.price
可能不正确,但这不会被检测到,因为它们将与
类型为.name
的元素匹配

因此,我希望能够找到具有LPM的元素,因为它是
类型.name
,我可以保证其中只有一个,然后对于
状态.id
状态.source
,和
状态.price
,只检查该元素,即不是ST元素

我试图修改我的body matcher,以找到我需要的
类型.name
的元素,但我无法实现这一点,因为我不知道如何在树上来回检查同一元素中的其他属性:

response.then()
        .assertThat()
        .body("size", greaterThan(0))
        .body("$.findAll (it.type.name = LPM}.status.id ", hasItem(statusId))
        .body("$.findAll (it.type.name = LPM}.status.source", hasItem(sourceId))
        .body("$.findAll (it.type.name = LPM}.status.price", hasItem(price));
而且,即使这样做有效,它也会在树上搜索3次,而实际上一次就可以了

我的中段比赛现在已经通过了这个测试,但我想把它做好。我知道我可以将元素放入一个
列表中
,并从中计算出来,但是为了与我们的其他示例保持一致,我宁愿不这样做,尽管我目前看不到其他选项

我曾试图在文档、多个放心教程和示例中找到我要做的事情的示例,但我没有找到,所以这总是有可能实际上是不可能的。如果不是的话,我很乐意把它背后的理论传授给唐


感谢您的帮助。

这里有一种方法:

...
then().
        root("find {it.type.name == '%s'}.status").
        body("id", withArgs("LPM"), is(1)).
        body("price", withArgs("LPM"), is(1.20f)).
        body("source", withArgs("LPM"), is(172)).
        body("id", withArgs("ST"), is(10));
(显然,您也可以使用args将
提取到变量中,以避免重复)

find
是Groovy查找与谓词匹配的第一个元素(
{it.type.name=='%s'}
)的方法,
findAll
将始终返回一个列表


root
指示REST Assured使用在后续预期中使用的“根路径”(请参见)。

您坚持只在REST Assured下执行此操作吗?@GrzegorzGórkiewicz是的,我不想引入另一个测试框架。如果我不能按照我想要的方式来做,那么我会将json反序列化为一个列表并对其进行迭代。例如,我想使用Google的GSON来实例化一个JSONObject列表,然后用Hamcrest断言该列表包含一个具有所需属性的元素。谢谢!这很有效。这是一个非常优雅的解决方案;比必须反序列化JSON和迭代要简洁得多。