Hamcrest с MockMvc: проверьте, что ключ существует, но значение может быть null
я делаю некоторые тесты с 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))))
The 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 для каждого атрибута?
3 ответов
вы можете добавить следующую статическую фабрику matcher:
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()));
обязательно импортируйте организацию.hamcrest.ядро.Функция isnull
Я нашел это решение в этой блог:
.andExpect(jsonPath( "$.keyToNull").doesNotExist());
это работает для меня.