подсчитать членов с помощью jsonpath?

Можно ли подсчитать количество членов с помощью JsonPath?

Используя Spring mvc test, я тестирую контроллер, который генерирует

{"foo": "oof", "bar": "rab"}

с участием

standaloneSetup(new FooController(fooService)).build()
            .perform(get("/something").accept(MediaType.APPLICATION_JSON)).andExpect(status().isOk())
            .andExpect(jsonPath("$.foo").value("oof"))
            .andExpect(jsonPath("$.bar").value("rab"));

Я хотел бы убедиться, что в сгенерированном json нет других участников. Надеюсь, подсчитав их с помощью jsonPath. Является ли это возможным? Приветствуются и альтернативные решения.


person NA.    schedule 06.12.2012    source источник


Ответы (5)


Чтобы проверить размер массива: jsonPath("$", hasSize(4))

Для подсчета членов объекта: jsonPath("$.*", hasSize(4))


Т.е. чтобы проверить, что API возвращает массив из 4 элементов:

допустимое значение: [1,2,3,4]

mockMvc.perform(get(API_URL))
       .andExpect(jsonPath("$", hasSize(4)));

чтобы проверить, что API возвращает объект, содержащий 2 члена:

допустимое значение: {"foo": "oof", "bar": "rab"}

mockMvc.perform(get(API_URL))
       .andExpect(jsonPath("$.*", hasSize(2)));

Я использую Hamcrest версии 1.3 и Spring Test 3.2.5.

hasSize (int) javadoc

Примечание: вам необходимо включить зависимость hamcrest-library и import static org.hamcrest.Matchers.*;, чтобы hasSize () работал.

person lopisan    schedule 10.12.2013
comment
@mattb - при использовании Maven не добавляйте hamcrest-all в качестве зависимости, а используйте hamcrest-library: код .google.com / p / hamcrest / wiki / HamcrestDistributables. - person Adam Michalik; 03.11.2015
comment
Что делать, если человек не знает размера и хочет его получить? - person zygimantus; 02.11.2016
comment
@ menuka-ishan - я не думаю, что он устарел, согласно: MockMvcResultMatchers.jsonPath () javadoc - person lopisan; 16.01.2017
comment
@zygimantus вы должны подсчитать размер всех полей в вашем объекте / массиве либо из исходного кода, либо из средств разработчика веб-браузера, проверяющих ответ. - person cellepo; 13.09.2019
comment
Для котлина вам может потребоваться добавить аргумент типа следующим образом: .andExpect(jsonPath("$", hasSize<Array<Any>>(4))) - person JackMahoney; 23.11.2020

Вы также можете использовать методы внутри jsonpath, поэтому вместо

mockMvc.perform(get(API_URL))
   .andExpect(jsonPath("$.*", hasSize(2)));

ты можешь сделать

mockMvc.perform(get(API_URL))
   .andExpect(jsonPath("$.length()", is(2)));
person stalet    schedule 22.11.2018

Мы можем использовать функции JsonPath, например size() или length(), например:

@Test
public void givenJson_whenGetLengthWithJsonPath_thenGetLength() {
    String jsonString = "{'username':'jhon.user','email':'[email protected]','age':'28'}";

    int length = JsonPath
        .parse(jsonString)
        .read("$.length()");

    assertThat(length).isEqualTo(3);
}

Или просто парсим до net.minidev.json.JSONObject и получаем размер:

@Test
public void givenJson_whenParseObject_thenGetSize() {
    String jsonString = "{'username':'jhon.user','email':'[email protected]','age':'28'}";

    JSONObject jsonObject = (JSONObject) JSONValue.parse(jsonString);

    assertThat(jsonObject)
        .size()
        .isEqualTo(3);
}

Действительно, второй подход выглядит более эффективным, чем первый. Я сделал тест производительности JMH и получил следующие результаты:

| Benchmark                                       | Mode  | Cnt | Score       | Error        | Units |
|-------------------------------------------------|-------|-----|-------------|--------------|-------|
| JsonPathBenchmark.benchmarkJSONObjectParse      | thrpt | 5   | 3241471.044 | ±1718855.506 | ops/s |
| JsonPathBenchmark.benchmarkJsonPathObjectLength | thrpt | 5   | 1680492.243 | ±132492.697  | ops/s |

Пример кода можно найти здесь.

person JuanMoreno    schedule 06.08.2018

Сам сегодня разбирался с этим. Не похоже, что это реализовано в доступных утверждениях. Однако есть способ передать объект org.hamcrest.Matcher. С этим вы можете сделать что-то вроде следующего:

final int count = 4; // expected count

jsonPath("$").value(new BaseMatcher() {
    @Override
    public boolean matches(Object obj) {
        return obj instanceof JSONObject && ((JSONObject) obj).size() == count;
    }

    @Override
    public void describeTo(Description description) {
        // nothing for now
    }
})
person Ben    schedule 28.12.2012

если у вас нет com.jayway.jsonassert.JsonAssert в пути к классам (как в случае со мной), тестирование следующим образом может быть возможным обходным путем:

assertEquals(expectedLength, ((net.minidev.json.JSONArray)parsedContent.read("$")).size());

[примечание: я предполагал, что содержимое json всегда является массивом]

person Tanvir    schedule 27.11.2015