使用Hamcrest映射平等

时间:2010-03-24 16:08:21

标签: java collections hamcrest

我想使用hamcrest声明两个映射相等,即它们具有指向相同值的相同键集。

我目前最好的猜测是:

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

给出:

  

方法断言Assert类型中的(T,Matcher)不适用于参数(Set>,Matcher>>>)

我还研究了containsAll的变体,以及hamcrest包提供的其他一些变体。谁能指出我正确的方向?或者我是否必须编写自定义匹配器?

9 个答案:

答案 0 :(得分:49)

我提出的最短路径是两个陈述:

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

但你也可以这样做:

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

取决于地图的实现。

更新:实际上有一个语句独立于集合类型工作:

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

答案 1 :(得分:36)

有时Map.equals()就足够了。但有时您不知道测试下的代码会返回Map的类型,因此您不知道.equals()是否能正确地将代码返回的未知类型的地图与由您。或者您不希望使用此类测试绑定代码。

此外,单独构建地图以比较结果是恕我直言不是很优雅:

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()变体,它将匹配器作为参数而不是键和值的精确值。如果您需要除了每个键和值的相等测试之外的其他内容,这可能很有用。

答案 2 :(得分:2)

我赞成使用Guava ImmutableMap。它们支持Map.equals()并且易于构建。唯一的技巧是明确指定类型参数,因为hamcrest将采用ImmutableMap类型。

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

答案 3 :(得分:2)

现在可用的另一个选项是使用Hamcst的Cirneco extension。它有hasSameKeySet()(以及其他番石榴和#34;系列和#34;)的匹配器。 根据你的例子,它将是:

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>

答案 4 :(得分:1)

一种非常简单的方法是使用Guava的com.google.common.collect.Maps类中的实用程序方法。

assertThat(Maps.difference(map1,map2).areEqual(),is(true));

答案 5 :(得分:0)

Hamcrest现在有一个Matcher的尺寸集合。

org.hamcrest.collection.IsCollectionWithSize

答案 6 :(得分:0)

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

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

答案 7 :(得分:0)

如果您需要将一组结果与期望值进行比较,如果您选择使用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()); 的检查

答案 8 :(得分:0)

我来到这个线程测试与 groovy 和 org.hamcrest:hamcrest:2.2

不推荐使用方法 isIn,建议改用 is(in(...))

然而,in 是 groovy 中的关键字!

所以我结束了导入的别名:

import static org.hamcrest.Matchers.*
import static org.hamcrest.Matchers.in as matchIn
....
....
@Test
void myTestMethod() {
    Map expectedSubMap = [
            one: "One",
            three: "Three"
            ]
    Map result = getMapToTest()
    assertThat(expectedSubMap.entrySet(), everyItem(is(matchIn(result.entrySet()))))
}