contar membros com jsonpath?

103

É possível contar o número de membros usando JsonPath?

Usando o teste Spring mvc, estou testando um controlador que gera

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

com

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

Eu gostaria de ter certeza de que nenhum outro membro está presente no json gerado. Esperançosamente contando-os usando jsonPath. É possível? Soluções alternativas também são bem-vindas.

N / D.
fonte

Respostas:

233

Para testar o tamanho da matriz :jsonPath("$", hasSize(4))

Para contar membros do objeto :jsonPath("$.*", hasSize(4))


Ou seja, para testar se a API retorna uma matriz de 4 itens:

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

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

para testar se a API retorna um objeto contendo 2 membros:

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

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

Estou usando o Hamcrest versão 1.3 e Spring Test 3.2.5.RELEASE

hasSize (int) javadoc

Nota: Você precisa incluir a dependência da biblioteca do import static org.hamcrest.Matchers.*;hamcrest e para que o hasSize () funcione.

Lopisan
fonte
2
@mattb - se estiver usando Maven, não adicione hamcrest-allcomo uma dependência, mas use hamcrest-library: code.google.com/p/hamcrest/wiki/HamcrestDistributables
Adam Michalik
1
E se alguém não souber o tamanho e quiser obtê-lo?
zygimantus
2
@ menuka-ishan - Não acho que seja obsoleto, de acordo com: MockMvcResultMatchers.jsonPath () javadoc
lopisan
@zygimantus, você deve contar o tamanho de todos os campos em seu Objeto / Matriz, seja do código-fonte ou da inspeção das ferramentas de desenvolvedor do navegador da web da resposta.
cellepo
12

Você também pode usar os métodos dentro do jsonpath, então, em vez de

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

você pode fazer

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

Podemos usar funções JsonPath como size()ou length()assim:

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

Ou simplesmente analise net.minidev.json.JSONObjecte obtenha o tamanho:

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

Na verdade, a segunda abordagem parece ter um desempenho melhor do que a primeira. Fiz um teste de desempenho JMH e obtive os seguintes 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 |

O código de exemplo pode ser encontrado aqui .

SHoko
fonte
4

Tenho lidado com isso sozinho hoje. Não parece que isso esteja implementado nas asserções disponíveis. No entanto, existe um método para passar um org.hamcrest.Matcherobjeto. Com isso, você pode fazer algo como o seguinte:

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

se você não tiver com.jayway.jsonassert.JsonAssertem seu classpath (que foi o meu caso), testar da seguinte maneira pode ser uma possível solução alternativa:

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

[nota: presumi que o conteúdo do json é sempre uma matriz]

Tanvir
fonte