我想使用 hamcrest 来断言两个映射是相等的,即它们具有指向相同值的相同的键集。
我目前最好的猜测是:
assertThat( affA.entrySet(), hasItems( affB.entrySet() );
给出:
类型
中的方法assertThat(T, Matcher<T>)
不适用于参数 (Assert
)Set<Map.Entry<Householdtypes,Double>>, Matcher<Iterable<Set<Map.Entry<Householdtypes,Double>>>>
我还研究了
containsAll
的变体,以及 hamcrest 包提供的其他一些变体。有人能指出我正确的方向吗?或者我必须编写一个自定义匹配器吗?
我想出的最短的方法是两个陈述:
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().toArray())));
有时
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()
的另一种变体,它将匹配器作为参数,而不是键和值的精确值。如果您需要除每个键和值的相等性测试之外的其他东西,这可能很有用。
我喜欢使用Guava ImmutableMap。它们支持
Map.equals()
并且易于构建。唯一的技巧是显式指定类型参数,因为 hamcrest 将采用 ImmutableMap
类型。
assertThat( actualValue,
Matchers.<Map<String, String>>equalTo( ImmutableMap.of(
"key1", "value",
"key2", "other-value"
) ) );
这就像一个魅力,不需要像接受的答案那样的两个断言。
assertThat( actualData.entrySet().toArray(),
arrayContainingInAnyOrder(expectedData.entrySet().toArray()) );
现在可用的另一个选项是使用 Hamcrest 的 Cirneco 扩展。它有
hasSameKeySet()
(以及番石榴“集合”的其他匹配器)。
根据你的例子,它将是:
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
如果您需要将一组结果与预期进行比较,并且选择使用 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());
一个非常简单的方法是使用 Guava 的 com.google.common.collect.Maps 类中的实用方法。
assertThat(Maps.difference(map1,map2).areEqual(),is(true));
我用 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()))))
}