Я провожу несколько тестов с MockMvc и хочу проверить структуру ответа JSON. В частности, я хочу убедиться, что ключ к атрибуту существует и что значение имеет определенный тип или значение null.
{
"keyToNull": null, # This may be null, or a String
"keyToString": "some value"
}
Для меня работает следующее, но мне интересно, есть ли способ объединить каждую группу из двух ожиданий в одну строку, так как у меня есть много атрибутов для проверки:
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);
Есть ли какой-нибудь умный Hamcrest Matcher, который я мог бы применить к одному пути json для каждого атрибута?