Reputation: 1581
I have limited experience with rest assured. We have a number of tests that I can usually find examples within, or failing that google, but I am stuck when trying to match on a nested property for an element in an anonymous array, and verify properties up across and down (cousins?).
Example 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
}
}
]
I'm using rest assured, and I want to find the element in the list that has type.name
equal to LPM, and then validate status.price
, status.source
, and status.id
of only that element.
When I initially started validating the responses, it was only possible for one item to be in the array, so I was using:
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));
However this is no longer assured to work, as there may be more than one element in the array, and the order is not guaranteed.
I have modified my body checks to be:
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));
This is enough to get the test to pass, but this introduces the risk that the status.id
, status.source
, and status.price
of the element with type.name
LPM could be incorrect, but this would not be detected as they would be matched against the element with type.name
ST.
So I want to be able to find the element which has LPM as it's type.name
, of which I can guarantee there to be only one, and then for status.id
, status.source
, and status.price
, check that element only, i.e. NOT the ST element.
I tried to modify my body matcher to find the elements with the type.name
that I need, but I can't get this to work, as I can't figure out how to go back up the tree, across and down, to check other attributes in the same element:
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));
Also even if this worked, it would search the tree 3 times when really once would have done.
My middle matches have this test passing for now but I want to get this right. I'm aware I could get the elements into a List
and work it out from there, but for consistency with the rest of our examples I'd rather not, though I currently can't see another option.
I have tried to find examples of what I'm trying to do in documentation, multiple rest assured tutorials and examples but I haven't, so there is always the possibility that this isn't actually possible. If not I'm happy to educate don the theory behind it.
Any help appreciated.
Upvotes: 3
Views: 16149
Reputation: 40510
Here's one way to do it:
...
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));
(you can obviously extract withArgs
to a variable as well to avoid repetition).
find
is Groovy's way of finding the first element matching the predicate ({it.type.name == '%s'}
), findAll
will always return a list.
root
instructs REST Assured to use a "root path" that is used in subsequent expectations (see docs).
Upvotes: 18