compter les membres avec jsonpath?

103

Est-il possible de compter le nombre de membres utilisant JsonPath?

En utilisant le test Spring MVC, je teste un contrôleur qui génère

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

avec

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

Je voudrais m'assurer qu'aucun autre membre n'est présent dans le json généré. Espérons en les comptant en utilisant jsonPath. C'est possible? Des solutions alternatives sont également les bienvenues.

N / A.
la source

Réponses:

233

Pour tester la taille du tableau :jsonPath("$", hasSize(4))

Pour compter les membres de l' objet :jsonPath("$.*", hasSize(4))


Ie pour tester que l'API renvoie un tableau de 4 éléments:

valeur acceptée: [1,2,3,4]

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

pour tester que l'API renvoie un objet contenant 2 membres:

valeur acceptée: {"foo": "oof", "bar": "rab"}

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

J'utilise Hamcrest version 1.3 et Spring Test 3.2.5.

hasSize (int) javadoc

Remarque: Vous devez inclure la dépendance hamcrest-library et import static org.hamcrest.Matchers.*;que hasSize () fonctionne.

lopisan
la source
2
@mattb - si vous utilisez Maven, ne l'ajoutez pas en hamcrest-alltant que dépendance, mais utilisez hamcrest-library: code.google.com/p/hamcrest/wiki/HamcrestDistributables
Adam Michalik
1
Et si l'on ne connaît pas la taille et veut l'obtenir?
zygimantus
2
@ menuka-ishan - Je ne pense pas que ce soit obsolète, selon: MockMvcResultMatchers.jsonPath () javadoc
lopisan
@zygimantus, vous devez compter la taille de tous les champs de votre objet / tableau, soit à partir du code source ou de l'inspection des outils de développement du navigateur Web de la réponse.
cellepo
12

Vous pouvez également utiliser les méthodes à l'intérieur du jsonpath, donc au lieu de

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

tu peux faire

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

Nous pouvons utiliser des fonctions JsonPath comme size()ou length(), comme ceci:

@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 simplement analyser net.minidev.json.JSONObjectet obtenir la taille:

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

En effet, la deuxième approche semble plus performante que la première. J'ai fait un test de performance JMH et j'obtiens les résultats suivants:

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

L'exemple de code peut être trouvé ici .

SHoko
la source
4

J'en ai géré moi-même aujourd'hui. Il ne semble pas que cela soit implémenté dans les assertions disponibles. Cependant, il existe une méthode pour passer un org.hamcrest.Matcherobjet. Avec cela, vous pouvez faire quelque chose comme ce qui suit:

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
la source
0

si vous ne l'avez pas com.jayway.jsonassert.JsonAssertsur votre chemin de classe (ce qui était le cas avec moi), tester de la manière suivante peut être une solution de contournement possible:

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

[note: j'ai supposé que le contenu du json est toujours un tableau]

Tanvir
la source