contar miembros con jsonpath?

103

¿Es posible contar la cantidad de miembros que usan JsonPath?

Usando la prueba spring mvc , estoy probando un controlador que 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"));

Me gustaría asegurarme de que no haya otros miembros presentes en el json generado. Con suerte, contándolos usando jsonPath. ¿Es posible? Las soluciones alternativas también son bienvenidas.

N / A.
fuente

Respuestas:

233

Para probar el tamaño de la matriz :jsonPath("$", hasSize(4))

Para contar miembros del objeto :jsonPath("$.*", hasSize(4))


Es decir, para probar que la API devuelve una matriz de 4 elementos:

valor aceptado: [1,2,3,4]

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

para probar que la API devuelve un objeto que contiene 2 miembros:

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

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

Estoy usando Hamcrest versión 1.3 y Spring Test 3.2.5.

hasSize (int) javadoc

Nota: Debe incluir la dependencia de la biblioteca import static org.hamcrest.Matchers.*;hamcrest y que hasSize () funcione.

lopisan
fuente
2
@mattb: si usa Maven, no agregue hamcrest-allcomo una dependencia, sino use hamcrest-library: code.google.com/p/hamcrest/wiki/HamcrestDistributables
Adam Michalik
1
¿Qué pasa si uno no conoce el tamaño y quiere conseguirlo?
zygimantus
2
@ menuka-ishan - No creo que esté obsoleto, de acuerdo con: MockMvcResultMatchers.jsonPath () javadoc
lopisan
@zygimantus debe contar el tamaño de todos los campos en su Objeto / Matriz, ya sea desde el código fuente o desde la inspección de las herramientas de desarrollo del navegador web de la respuesta.
cellepo
12

También puede usar los métodos dentro de jsonpath, así que en lugar de

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

tu puedes hacer

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

Podemos usar funciones de JsonPath como size()o length(), así:

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

O simplemente analizando net.minidev.json.JSONObjecty obteniendo el tamaño:

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

De hecho, el segundo enfoque parece funcionar mejor que el primero. Hice una prueba de rendimiento de JMH y obtengo los siguientes resultados:

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

El código de ejemplo se puede encontrar aquí .

SHoko
fuente
4

He estado lidiando con esto yo mismo hoy. No parece que esto esté implementado en las afirmaciones disponibles. Sin embargo, existe un método para pasar un org.hamcrest.Matcherobjeto. Con eso puedes hacer algo como lo siguiente:

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

si no lo tiene com.jayway.jsonassert.JsonAsserten su classpath (que fue mi caso), probar de la siguiente manera puede ser una posible solución:

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

[nota: asumí que el contenido del json es siempre una matriz]

Tanvir
fuente