Как использовать Hamcrest для проверки элементов карты
Недавно я использовал библиотеку Hamcrest для написания тестов и довольно успешную, но теперь мне нужно сделать что-то более сложное и начать видеть много трудностей. Мне нужно inpsect и проверить свойства элементов на карте. Мой производственный код выглядит примерно так:
Map<String, List<MyItem>> map = new HashMap<String, List<MyItem>>();
map.put("one", Arrays.asList(new MyItem("One")));
map.put("two", Arrays.asList(new MyItem("Two")));
map.put("three", Arrays.asList(new MyItem("Three")));
Я хочу написать несколько тестовых кодов, подобных следующим, но он не компилируется. Похоже, что Hamcrest hasEntry имеет параметризацию по типу, а hasItem и hasProperty только ожидают Object.
assertThat(map, Matchers.<String, List<MyItem>>hasEntry("one", hasItem(hasProperty("name", is("One")))));
В моей среде IDE (Eclipse) появляется следующее сообщение об ошибке: Параметрированный метод <String, List<HamcrestTest.MyItem>>hasEntry(String, List<HamcrestTest.MyItem>)
типа Matchers
неприменим для аргументов (String, Matcher<Iterable<? super Object>>)
. С одной стороны, я думаю, что Eclipse запутался в том, какой метод hasEntry
я хотел использовать, он должен быть hasEntry(org.hamcrest.Matcher<? super K> keyMatcher, org.hamcrest.Matcher<? super V> valueMatcher)
, а не hasEntry(K key, V value)
.
Должен ли я просто сдаться и получить предмет с Карты и вручную проверить каждое свойство? Есть ли более чистый способ?
Ответы
Ответ 1
Вы можете просто использовать contains
или containsInAnyOrder
. Правда, вам придется перечислить все элементы в List
таким образом, но он работает более чисто, чем hasItem
:
@SuppressWarnings("unchecked")
@Test
public void mapTest() {
Map<String, List<MyItem>> map = new HashMap<String, List<MyItem>>();
map.put("one", asList(new MyItem("1"), new MyItem("one")));
assertThat(map, hasEntry(is("one"),
containsInAnyOrder(hasProperty("name", is("one")),
hasProperty("name", is("1")))));
}
Ответ 2
Чтобы просто сделать это проще, вы можете попробовать это...
assertThat((Object)map, (Matcher)Matchers.hasEntry("one", hasItem(hasProperty("name", is("One")))));
перейдя на необработанный тип, вы получите предупреждение, но не скомпилируете ошибку. Если вы использовали этот трюк в прошлом, когда я не хочу беспокоиться о том, чтобы все литье было правильно для компилятора.
Кроме того, вы можете использовать ItIterableContainingInOrder.containingInOrder(new MyItem("One")))
. Это проверит весь список, и если MyItem
реализует equals
, вы не будете использовать отражение в своих тестах.
Ответ 3
Так как @t0mppa не предоставил хороший пример того, как использовать Hamcrest contains
и containsInAnyOrder
для этого, вот немного чего начать:
Map<Integer, String> columns = new HashMap<Integer, String>();
columns.put(1, "ID");
columns.put(2, "Title");
columns.put(3, "Description");
assertThat(columns.values(), contains("ID", "Title", "Description")); // passes
assertThat(columns.values(), contains("ID", "Description", "Title")); // fails
assertThat(columns.values(), containsInAnyOrder("ID", "Description", "Title")); // passes
Обратите внимание, что в отличие от hasItem
и hasItems
, они будут работать, только если вы предоставите им полный список всех значений, с которыми вы будете сопоставлять. Подробнее см. Hamcrest javadocs.