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.

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.


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

7

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

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

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

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

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 .


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

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]

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.