我最近使用Hamcrest库编写了一些测试并且相当成功,但现在我需要做一些更复杂的事情并开始看到很多困难。我需要inpsect并验证Map中项目的属性。我的生产代码看起来像这样:
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)
。
我应该放弃并从地图中获取项目并手动检查每个属性吗?有更清洁的方式吗?
答案 0 :(得分:29)
Youu可以使用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")))));
}
答案 1 :(得分:5)
所以只是为了让这个更简单,你可以试试这个......
assertThat((Object)map, (Matcher)Matchers.hasEntry("one", hasItem(hasProperty("name", is("One")))));
通过转到原始类型,您将收到警告但没有编译错误。如果过去我曾经使用过这个技巧,那么我不想担心所有的编译都适合编译器。
另外,您可以考虑使用ItIterableContainingInOrder.containingInOrder(new MyItem("One")))
。这将验证整个列表,如果MyItem
实现equals
,那么您将不会在测试中使用反射。
答案 2 :(得分:4)
由于@ 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。
答案 3 :(得分:0)
hasEntry
方法有两个签名:
hasEntry(key, value)
hasEntry(matcher<key>, matcher<value>)
您正在使用第一个签名,因此您正在检查您的地图是否包含映射到字符串“one”的匹配器。 t0mppa's answer 正在使用第二个签名,这就是它起作用的原因。好消息是你不需要列出列表中的所有元素,你可以
assertThat(map, hasEntry(is("one"), hasItem(hasProperty("name", is("One")))));