Hamcrest测试地图包含来自另一个地图的所有条目

时间:2014-01-17 12:45:12

标签: java hamcrest

我想检查地图是否包含某组条目。允许包含不在expectedMap中的其他条目。我目前有以下断言:

assertThat(expectedMap.entrySet(), everyItem(isIn(actualMap.entrySet())));

尽管这确实有效,但它打印的失败消息令人困惑,因为预期和接收的参数已从正常使用中反转。有没有更好的方法来写它?

1 个答案:

答案 0 :(得分:8)

hasItems做你想要的,但是以一种非显而易见的方式。你必须跳过一些箍,因为Hamcrest对匹配Iterable的支持相对有限。 (没有详细说明,这是由于Java泛型如何工作的变幻莫测 - 我将在稍后发布一些更详细的链接。)

(我假设您使用的是泛型,例如Map<String, String>,而不是Map。)

与此同时,您有几个选择......

如果您对在测试中使用@SuppressWarnings("unchecked")发出警告的测试代码感到满意:

assertThat(actualMap.entrySet(), (Matcher)hasItems(expectedMap.entrySet().toArray()));

说明:hasItems没有重载需要SetIterable,但需要一个数组。 Set.toArray()会返回Object[],但assertThat与您的actualMap.entrySet()不匹配 - 但如果您删除了匹配器的声明类型,则会很乐意继续进行。

如果你想要一个在没有警告的情况下进行编译的断言,它会变得更加丑陋 - 你需要将Set复制到某种Iterable<Object>(你不能强制转换)以便匹配对象:

assertThat(new HashSet<Object>(actualMap.entrySet()), hasItems(expectedMap.entrySet().toArray()));

但是说实话,为了清楚起见,你几乎肯定最好单独断言每个条目:

for (Entry<String, String> entry : expectedMap.entrySet()) {
    assertThat(actualMap, hasEntry(entry.getKey(), entry.getValue())); 
}

...或者你可以编写自己的匹配器 - 有很多关于如何在线和在线进行此操作的资源。