Hamcrest测试一个Map是否包含另一个Map的所有条目

9

我想检查一个地图是否包含一组特定的条目。它可以包含其他不在expectedMap中的条目。我目前有以下断言:

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

虽然这个方法可以正常工作,但是它打印的错误信息可能会让人困惑,因为预期的和接收到的参数与正常用法相反。有没有更好的方法来书写它?
1个回答

12

hasItems可以完成你想要的功能,但是实现方式并不明显。由于Hamcrest对匹配Iterable的支持相对较少,你需要跨越一些障碍。(不详细解释,这是由于Java泛型的机制导致的——稍后我会发布一些更详细的链接)。

(假设你正在使用泛型,例如Map<String, String>而不是简单的Map)。

同时,您有几个选项...

如果你接受会引发警告的测试代码或者在你的测试中使用@SuppressWarnings("unchecked"):

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

解释:没有重载接受SetIterablehasItems方法,但会接受数组。Set.toArray()返回Object[],它与你的actualMap.entrySet()不匹配,无法通过assertThat断言。但是,如果你抹掉Matcher的声明类型,它就可以顺利进行。

如果你想要一个不带警告编译的断言,情况就会变得更加复杂 - 你需要将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())); 
}

或者你可以编写自己的 Matcher - 在网上和 SO 上有很多关于如何做到这一点的资源。


是的,我问的一个原因是因为我不满意警告或转换。这很丑陋。我同意最后一个选项现在可能是最好的。过去我写过几个匹配器,如果我需要再做一次,我会写一个匹配器来处理它。 - z7sg Ѫ

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接