MockMvcでいくつかのテストを行っていますが、JSON応答の構造を検証したいと思います。具体的には、属性のキーが存在し、値が特定のタイプまたはnullであることを確認したいと思います。
_{
"keyToNull": null, # This may be null, or a String
"keyToString": "some value"
}
_
以下は私にとってはうまくいきますが、チェックする属性がたくさんあるので、2つの期待の各グループを1つの行に結合する方法があるかどうか疑問に思っています:
_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))))
_
hasKey()
が必要なのは、MockMvcの実装に存在しないキーがnullにマップされるため、他のアサーション自体が渡されるためです。
_.andExpect(jsonPath("$.notAKey").value(
anyOf(any(String.class), nullValue(String.class)))) // ok
_
jsonPath().exists()
も機能しません。これは、内部的に値をnull
と比較するためです。
私はこのような別の方法を作ることを考えました:
_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))));
}
_
しかし、それは私に不自然な方法で私のコードを分割することを強制します:
_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);
_
属性ごとに1つのjsonパスに適用できる巧妙なハムクレストマッチャーはありますか?
次の静的マッチャーファクトリを追加できます。
public static <K> Matcher<Map<? extends K, ?>> hasNullKey(K key) {
return new IsMapContaining<K,Object>(equalTo(key), anyOf(nullValue(), anyString());
}
そして、次のように使用できます。
// 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")))
この操作は、次の既存のテストクラスで実行できます。
.andExpect(jsonPath("$..myExpectedNullKey[0]").value(IsNull.nullValue()));
必ずorg.hamcrest.core.IsNullをインポートしてください