liczyć członków z jsonpath?

103

Czy można policzyć liczbę członków za pomocą JsonPath?

Używając testu wiosennego MVC testuję kontroler, który generuje

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

z

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"));

Chciałbym się upewnić, że w wygenerowanym pliku JSON nie ma innych członków. Mamy nadzieję, że licząc je za pomocą jsonPath. Czy to możliwe? Alternatywne rozwiązania również są mile widziane.

NA.
źródło

Odpowiedzi:

233

Aby przetestować rozmiar tablicy :jsonPath("$", hasSize(4))

Aby policzyć członków obiektu :jsonPath("$.*", hasSize(4))


To znaczy, aby przetestować, czy API zwraca tablicę 4 elementów:

akceptowana wartość: [1,2,3,4]

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

aby przetestować, czy API zwraca obiekt zawierający 2 elementy:

akceptowana wartość: {"foo": "oof", "bar": "rab"}

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

Używam Hamcrest w wersji 1.3 i Spring Test 3.2.5.RELEASE

hasSize (int) javadoc

Uwaga: Musisz uwzględnić zależność hamcrest-library i import static org.hamcrest.Matchers.*;aby funkcja hasSize () działała.

lopisan
źródło
2
@mattb - jeśli używasz Mavena, nie dodawaj hamcrest-alljako zależności, ale użyj hamcrest-library: code.google.com/p/hamcrest/wiki/HamcrestDistributables
Adam Michalik
1
A jeśli nie znasz rozmiaru i chcesz go zdobyć?
zygimantus
2
@ menuka-ishan - Nie sądzę, że jest przestarzałe, zgodnie z: MockMvcResultMatchers.jsonPath () javadoc
lopisan
@zygimantus musisz policzyć rozmiar wszystkich pól w swoim obiekcie / tablicy, albo na podstawie kodu źródłowego, albo narzędzia programistycznego przeglądarki internetowej, sprawdzającego odpowiedź.
cellepo
12

Możesz również użyć metod wewnątrz jsonpath, więc zamiast

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

możesz to zrobić

mockMvc.perform(get(API_URL))
   .andExpect(jsonPath("$.length()", is(2)));
stalet
źródło
7

Możemy użyć funkcji JsonPath, takich jak size()lub length(), takich jak:

@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);
}

Lub po prostu przeanalizuj net.minidev.json.JSONObjecti pobierz rozmiar:

@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);
}

Rzeczywiście, drugie podejście wydaje się działać lepiej niż pierwsze. Wykonałem test wydajności JMH i otrzymałem następujące wyniki:

| 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 |

Przykładowy kod można znaleźć tutaj .

SHoko
źródło
4

Sam sobie z tym dzisiaj radziłem. Wydaje się, że nie jest to zaimplementowane w dostępnych asercjach. Istnieje jednak metoda przekazywania org.hamcrest.Matcherobiektu. Dzięki temu możesz zrobić coś takiego:

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
    }
})
Ben
źródło
0

jeśli nie masz com.jayway.jsonassert.JsonAssertna swojej ścieżce klas (co miało miejsce w przypadku mnie), testowanie w następujący sposób może być możliwym obejściem:

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

[uwaga: założyłem, że zawartość json jest zawsze tablicą]

Tanvir
źródło