contare i membri con jsonpath?


103

È possibile contare il numero di membri utilizzando JsonPath?

Utilizzando spring mvc test sto testando un controller che genera

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

con

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

Vorrei assicurarmi che nessun altro membro sia presente nel json generato. Si spera contandoli usando jsonPath. È possibile? Sono benvenute anche soluzioni alternative.

Risposte:


233

Per testare la dimensione dell'array :jsonPath("$", hasSize(4))

Per contare i membri dell'oggetto :jsonPath("$.*", hasSize(4))


Cioè per testare che l'API restituisce un array di 4 elementi:

valore accettato: [1,2,3,4]

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

per verificare che l'API restituisca un oggetto contenente 2 membri:

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

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

Sto usando Hamcrest versione 1.3 e Spring Test 3.2.5.RELEASE

hasSize (int) javadoc

Nota: è necessario includere la dipendenza hamcrest-library e import static org.hamcrest.Matchers.*;affinché hasSize () funzioni.


2
@mattb - se usi Maven, non aggiungere hamcrest-allcome dipendenza, ma usa hamcrest-library: code.google.com/p/hamcrest/wiki/HamcrestDistributables
Adam Michalik

1
Cosa succede se non si conosce la taglia e si vuole ottenerla?
zygimantus

2
@ menuka-ishan - Non credo sia deprecato, secondo: MockMvcResultMatchers.jsonPath () javadoc
lopisan

@zygimantus devi contare la dimensione di tutti i campi sul tuo oggetto / array, dal codice sorgente o dall'ispezione della risposta degli strumenti di sviluppo del browser web.
cellepo

12

Puoi anche usare i metodi all'interno di jsonpath, quindi invece di

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

tu puoi fare

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

7

Possiamo usare le funzioni JsonPath come size()o length(), in questo modo:

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

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

    assertThat(length).isEqualTo(3);
}

O semplicemente analizzando net.minidev.json.JSONObjecte ottenendo la dimensione:

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

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

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

In effetti, il secondo approccio sembra funzionare meglio del primo. Ho eseguito un test delle prestazioni JMH e ottengo i seguenti risultati:

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

Il codice di esempio può essere trovato qui .


4

Mi sono occupato di questo io stesso oggi. Non sembra che questo sia implementato nelle asserzioni disponibili. Tuttavia, esiste un metodo per passare un org.hamcrest.Matcheroggetto. Con ciò puoi fare qualcosa di simile al seguente:

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

0

se non hai com.jayway.jsonassert.JsonAssertsul tuo classpath (come era il caso con me), testare nel modo seguente potrebbe essere una possibile soluzione:

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

[nota: presumo che il contenuto del json sia sempre un array]

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.