Hamcrest avec MockMvc: vérifiez que la clé existe mais que la valeur peut être nulle

je fais quelques tests avec MockMvc, et je veux valider la structure d'une réponse JSON. Spécifiquement, je veux m'assurer que la clé d'un attribut existe, et que la valeur est d'un certain type ou null.

{
   "keyToNull": null,  # This may be null, or a String
   "keyToString": "some value"
}

fonctionne pour moi, mais je me demandais si il existe un moyen de combiner chaque groupe de deux attentes, en une seule ligne, comme j'ai beaucoup d'attributs à vérifier:

import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
import static org.hamcrest.Matchers.*;

.andExpect(jsonPath("$").value(hasKey("keyToNull")))
.andExpect(jsonPath("$.keyToNull").value(
                  anyOf(any(String.class), nullValue(String.class))))

.andExpect(jsonPath("$").value(hasKey("keyToString")))
.andExpect(jsonPath("$.keyToString").value(
                  anyOf(any(String.class), nullValue(String.class))))

le hasKey() est nécessaire parce que l'autre assertion passe par elle-même depuis des clés inexistantes dans la carte d'implémentation de MockMvc à null:

.andExpect(jsonPath("$.notAKey").value(
                  anyOf(any(String.class), nullValue(String.class)))) // ok

jsonPath().exists() ne fonctionne pas non plus, car à l'interne il compare la valeur contre null .

j'ai envisagé de faire une méthode séparée comme celle-ci:

private static <T> void assertNullableAttr(ResultActions res, String jsonPath, Class<T> type) throws Exception {
    int split = jsonPath.lastIndexOf('.');
    String prefix = jsonPath.substring(0, split), key = jsonPath.substring(split+1);

    res.andExpect(jsonPath(prefix).value(hasKey(key)))
        .andExpect(jsonPath(jsonPath).value(anyOf(any(type), nullValue(type))));
    }

mais alors il me force à diviser mon code d'une manière anormale:

ResultActions res = mockMvc.perform(get("/api"))
    // these attributes must not be null
    .andExpect(jsonPath("$.someInfo").value(hasSize(2)))
        .andExpect(jsonPath("$.someInfo[0].info1").value(any(String.class)))
        .andExpect(jsonPath("$.someInfo[0].info2").value(any(String.class)))
    .andExpect(jsonPath("$.addlInfo").value(hasSize(2)))
        .andExpect(jsonPath("$.addlInfo[0].info1").value(any(String.class)))
        .andExpect(jsonPath("$.addlInfo[0].info2").value(any(String.class)));

// these attributes may be null
assertNullableAttr(res, "$.someInfo[0].info3", String.class);
assertNullableAttr(res, "$.someInfo[0].info4", String.class);

assertNullableAttr(res, "$.addlInfo[0].info3", String.class);
assertNullableAttr(res, "$.addlInfo[0].info4", String.class);

Est-il un intelligent Hamcrest Matcher je pourrais appliquer à un seul chemin json par attribut?

6
demandé sur Yonatan 2014-08-15 02:16:15

3 réponses

Vous pouvez ajouter le suivant statique matcher usine:

public static <K> Matcher<Map<? extends K, ?>> hasNullKey(K key) {
    return new IsMapContaining<K,Object>(equalTo(key), anyOf(nullValue(), anyString());
}

Et puis, vous pouvez l'utiliser comme ceci:

// will succeed, because keyToNull exists and null
.andExpect(jsonPath("$").value(hasNullKey("keyToNull")))

// will succeed, bacause keyToString exists and not null
.andExpect(jsonPath("$").value(hasNullKey("keyToString")))

// will fail, because notAKey doesn't exists
.andExpect(jsonPath("$").value(hasNullKey("notAKey")))
4
répondu Yonatan 2014-10-21 06:41:22

vous pouvez effectuer cette opération avec les classes de test existantes suivantes:

.andExpect(jsonPath("$..myExpectedNullKey[0]").value(IsNull.nullValue()));

n'oubliez pas d'importer org.hamcrest.core.IsNull

13
répondu Jeremy D 2015-02-18 18:38:27

j'ai trouvé cette solution dans ce blog :

.andExpect(jsonPath( "$.keyToNull").doesNotExist());

ça me va.

2
répondu nacho 2017-09-12 15:13:40