I'm using JsonPath to test REST endpoints of my API. My test case looks something like this.
First I create the new object
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);
Then I get a list of all items and check that the item I just created is in the list.
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();
Which works, but I dont think I'm doing it right because I have a nested contains(contains())
. (I've put the full JSON response at the end of this post.)
The problem is that because the JsonPath expressions are returning a list, I need to use a list matcher. For example, instead of writing this
jsonPath("$.data[?(@.id == 1)].name", is("item 1"))
I need to write it like this
jsonPath("$.data[?(@.id == 1)].name", contains("item 1"))
Because the JsonPath expression will return a JSON list of one element
[
"item 1"
]
Which isn't so bad, but it gets worse with lists, e.g. trying to check if the List of Strings in my variable places contains what I want. The JSON returned is a List of Lists, so this JsonPath expression
jsonPath("$.data[?(@.id == 1)].places"
Will return this
[
[
"Rome2",
"London3",
"Paris3"
]
]
So it requires a nested hasItems
jsonPath("$.data[?(@.id == 1)].places", hasItems(hasItems("Rome1", "London1")))
And at that works, but doing this just gives me that feeling that I'm not doing this correctly and I'm missing something.
So my question is, what is the appropriate way to handle checking/matching a list of lists?
Is there a better way to validate the JSON that is being returned by an endpoint?