使用Hamcrest地图平等

我想用hamcrest来声明两个地图是平等的,也就是说,它们有相同的一组键指向相同的值。

我目前最好的猜测是:

assertThat( affA.entrySet(), hasItems( affB.entrySet() ); 

这使:

Asserttypes中的assertThat(T,Matcher)不适用于参数(Set>,Matcher >>>)

我也研究了containsAll的变体,还有一些由hamcrest包提供的变体。 任何人都可以指向正确的方向吗? 还是我必须写一个自定义的匹配器?

我提出的最短路线是两条语句:

 assertThat( affA.entrySet(), everyItem(isIn(affB.entrySet()))); assertThat( affB.entrySet(), everyItem(isIn(affA.entrySet()))); 

但你也可以做:

 assertThat(affA.entrySet(), equalTo(affB.entrySet())); 

取决于地图的实现。

更新:实际上有一个独立于集合types的语句:

 assertThat(affA.entrySet, both(everyItem(isIn(affB.entrySet()))).and(containsInAnyOrder(affB.entrySet()))); 

有时Map.equals()就够了。 但有时你不知道在testing下代码返回的Maptypes,所以你不知道.equals()是否会正确地比较由你构造的地图代码返回的未知types的地图。 或者你不想用这样的testing来绑定你的代码。

此外,分别构build一个地图来比较结果是恕我直言,不是很优雅:

 Map<MyKey, MyValue> actual = methodUnderTest(); Map<MyKey, MyValue> expected = new HashMap<MyKey, MyValue>(); expected.put(new MyKey(1), new MyValue(10)); expected.put(new MyKey(2), new MyValue(20)); expected.put(new MyKey(3), new MyValue(30)); assertThat(actual, equalTo(expected)); 

我更喜欢使用马歇尔:

 import static org.hamcrest.Matchers.hasEntry; Map<MyKey, MyValue> actual = methodUnderTest(); assertThat(actual, allOf( hasSize(3), // make sure there are no extra key/value pairs in map hasEntry(new MyKey(1), new MyValue(10)), hasEntry(new MyKey(2), new MyValue(20)), hasEntry(new MyKey(3), new MyValue(30)) )); 

我必须自己定义hasSize()

 public static <K, V> Matcher<Map<K, V>> hasSize(final int size) { return new TypeSafeMatcher<Map<K, V>>() { @Override public boolean matchesSafely(Map<K, V> kvMap) { return kvMap.size() == size; } @Override public void describeTo(Description description) { description.appendText(" has ").appendValue(size).appendText(" key/value pairs"); } }; } 

还有hasEntry()另一个变体,它将匹配器作为参数,而不是键和值的确切值。 如果您需要除每个键和值的平等testing之外的其他内容,这可能会很有用。

我喜欢使用番石榴ImmutableMap 。 他们支持Map.equals()并且很容易构造。 唯一的技巧是明确指定types参数,因为hamcrest将假定ImmutableMaptypes。

 assertThat( actualValue, Matchers.<Map<String, String>>equalTo( ImmutableMap.of( "key1", "value", "key2", "other-value" ) ) ); 

现在可用的另一种select是使用Hamcrest的Cirneco扩展 。 它有hasSameKeySet() (以及Guava“collections”的其他匹配器)。 根据你的例子,这将是:

 assertThat(affA, hasSameKeySet(affB)); 

您可以对基于JDK7的项目使用以下依赖项:

 <dependency> <groupId>it.ozimov</groupId> <artifactId>java7-hamcrest-matchers</artifactId> <version>0.7.0</version> </dependency> 

或者如果您使用的是JDK8或更高版本,请使用以下命令:

 <dependency> <groupId>it.ozimov</groupId> <artifactId>java8-hamcrest-matchers</artifactId> <version>0.7.0</version> </dependency> 

Hamcrest现在有一个Matcher的大小收集。

org.hamcrest.collection.IsCollectionWithSize

这就像一个魅力,并不需要像接受的答案一样的两个断言。

 assertThat( actualData.entrySet().toArray(), arrayContainingInAnyOrder(expectedData.entrySet().toArray()) ); 

如果您需要将一组结果与预期进行比较,并且您select使用assertj库,则可以这样做:

 // put set of expected values by your test keys Map<K, V> expectations = ...; // for each test key get result Map<K, V> results = expectations.keySet().stream().collect(toMap(k -> k, k -> getYourProductionResult(k))); assertThat(results).containsAllEntriesOf(expectations); 

请注意, containsAllEntriesOf不会比较地图的相等性。 如果您的产品代码实际返回一个Map<K, V>您可能需要添加一个检查关键字assertThat(results).containsOnlyKeys((K[]) expectations.keySet().toArray());