Search code examples
javaspringtestingjsonpathhamcrest

Spring JsonPath contains in any order exception


I'm writing some integration tests with spring, and wanna check, that json from response contains all required data. See code:

@Test
public void getAll() throws Exception {
    String url = "/permissions/all";
    int size = 4;
    try {
        Set<String> permissions = RandomGenerator.randomStrings(size);
        initDb(permissions);
        mvc.perform(get(url).with(Users.PERMISSIONS_READ))
                .andExpect(jsonPath("$[?(@.name)].name", hasSize(size))) //ok
                .andExpect(jsonPath("$[?(@.name)].name").value(containsInAnyOrder(permissions))); //exception
    } finally {
        dropDb();
    }
}

But I'm getting an exception here:

java.lang.AssertionError: JSON path "$[?(@.name)].name"

Expected: iterable over [<[b0ce9e8a-8b62-41f4-91b9-d9cf6ff96675, 7ebe3a4f-7864-4ea5-92b3-a5ad6f44bf42, 7df2fa88-b22f-4d33-91b2-f8b00813522f, 17b61119-c48c-4dff-ac9c-047eb3efcc43]>] in any order
 but: Not matched: "7df2fa88-b22f-4d33-91b2-f8b00813522f"

And the data from this response:

[{
    "id": 1,
    "name": "7df2fa88-b22f-4d33-91b2-f8b00813522f" 
}, {
    "id": 2,
    "name": "b0ce9e8a-8b62-41f4-91b9-d9cf6ff96675"
}, {
    "id": 3,
    "name": "7ebe3a4f-7864-4ea5-92b3-a5ad6f44bf42"
}, {
    "id": 4,
    "name": "17b61119-c48c-4dff-ac9c-047eb3efcc43"
}]

I know, that selector $[?(@.name)].name works fine, and returns a following result:

[
  "7df2fa88-b22f-4d33-91b2-f8b00813522f",
  "b0ce9e8a-8b62-41f4-91b9-d9cf6ff96675",
  "7ebe3a4f-7864-4ea5-92b3-a5ad6f44bf42",
  "17b61119-c48c-4dff-ac9c-047eb3efcc43"
]

permissions set is also correct and contains 4 strings as in the sample above.

Can somebody tell me please what I'm doing wrong here?


Solution

  • This will work:

    Set<String> permissions = RandomGenerator.randomStrings(size);
    initDb(permissions);
    mvc.perform(get(url).with(Users.PERMISSIONS_READ))
        .andExpect(jsonPath("$[?(@.name)].name", hasSize(size))) //ok
        .andExpect(jsonPath("$[?(@.name)].name").value(containsInAnyOrder(permissions.toArray(new String[permissions.size()]))));
    

    Or restated:

    String[] permissions = RandomGenerator.randomStrings(size);
    initDb(permissions);
    mvc.perform(get(url).with(Users.PERMISSIONS_READ))
        .andExpect(jsonPath("$[?(@.name)].name", hasSize(size))) //ok
        .andExpect(jsonPath("$[?(@.name)].name").value(containsInAnyOrder(permissions)));
    

    Here's the signature of containsInAnyOrder:

    public static <T> Matcher<Iterable<? extends T>> containsInAnyOrder(T... items)
    

    So, it expects a varargs of the same type that you are asserting against. In your case you are asserting against the type String but you are supplying a Set<String> to containsInAnyOrder so the match between a String and a Set fails.