问题
I have the following JSON response for my REST endpoint:
{
"response": {
"status": 200,
"startRow": 0,
"endRow": 1,
"totalRows": 1,
"next": "",
"data": {
"id": "workflow-1",
"name": "SampleWorkflow",
"tasks": [
{
"id": "task-0",
"name": "AWX",
"triggered_by": ["task-5"]
},
{
"id": "task-1",
"name": "BrainStorming",
"triggered_by": ["task-2", "task-5"]
},
{
"id": "task-2",
"name": "OnHold",
"triggered_by": ["task-0", "task-4", "task-7", "task-8", "task9"]
},
{
"id": "task-3",
"name": "InvestigateSuggestions",
"triggered_by": ["task-6"]
},
{
"id": "task-4",
"name": "Mistral",
"triggered_by": ["task-3"]
},
{
"id": "task-5",
"name": "Ansible",
"triggered_by": ["task-3"]
},
{
"id": "task-6",
"name": "Integration",
"triggered_by": []
},
{
"id": "task-7",
"name": "Tower",
"triggered_by": ["task-5"]
},
{
"id": "task-8",
"name": "Camunda",
"triggered_by": ["task-3"]
},
{
"id": "task-9",
"name": "HungOnMistral",
"triggered_by": ["task-0", "task-7"]
},
{
"id": "task-10",
"name": "MistralIsChosen",
"triggered_by": ["task-1"]
}
]
}
}
}
I am using rest-assured with a groovy gpath expression for an extraction as follows:
given()
.when()
.get("http://localhost:8080/workflow-1")
.then()
.extract()
.path("response.data.tasks.findAll{ it.triggered_by.contains('task-3') }.name")
which correctly gives me [Mistral, Ansible, Camunda]
What I am trying to achieve is to find the task names that are triggered by the InvestigateSuggestions
task. But I don't know for sure that the taskId I have to pass in to contains()
is task-3
; I only know its name i.e. InvestigateSuggestions
. So I attempt to do:
given()
.when()
.get("http://localhost:8080/workflow-1")
.then()
.extract()
.path("response.data.tasks.findAll{
it.triggered_by.contains(response.data.tasks.find{
it.name.equals('InvestigateSuggestions')}.id) }.name")
which does not work and complains that the parameter "response" was used but not defined.
How do I iterate over the outer collection from inside the findAll closure to find the correct id
to pass into contains()
??
回答1:
You can make use of a dirty secret, the restAssuredJsonRootObject
. This is undocumented (and subject to change although it has never change as far as I can remember in the 7 year+ lifespan of REST Assured).
This would allow you to write:
given()
.when()
.get("http://localhost:8080/workflow-1")
.then()
.extract()
.path("response.data.tasks.findAll{
it.triggered_by.contains(restAssuredJsonRootObject.response.data.tasks.find{
it.name.equals('InvestigateSuggestions')}.id) }.name")
If you don't want to use this "hack" then you need to do something similar to what Michael Easter proposed in his answer.
When it comes to generating matchers based on the response body the story is better. See docs here.
回答2:
I'm not sure if this is idiomatic but one approach is to find the id
first and then substitute into another query:
@Test
void testCase1() {
def json = given()
.when()
.get("http://localhost:5151/egg_minimal/stacko.json")
// e.g. id = 'task-3' for name 'InvestigateSuggestions'
def id = json
.then()
.extract()
.path("response.data.tasks.find { it.name == 'InvestigateSuggestions' }.id")
// e.g. tasks have name 'task-3'
def tasks = json
.then()
.extract()
.path("response.data.tasks.findAll{ it.triggered_by.contains('${id}') }.name")
assertEquals(['Mistral', 'Ansible', 'Camunda'], tasks)
}
来源:https://stackoverflow.com/questions/52122487/nested-iteration-over-json-using-groovy-closure-in-rest-assured