Java 使用 Hamcrest 映射相等性

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2509293/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 08:38:00  来源:igfitidea点击:

Map equality using Hamcrest

javacollectionshamcrest

提问by mo-seph

I'd like to use hamcrest to assert that two maps are equal, i.e. they have the same set of keys pointing to the same values.

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

My current best guess is:

我目前最好的猜测是:

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

which gives:

这使:

The method assertThat(T, Matcher) in the type Assert is not applicable for the arguments (Set>, Matcher>>>)

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

I've also looked into variations of containsAll, and some others provided by the hamcrest packages. Can anyone point me in the right direction? Or do I have to write a custom matcher?

我还研究了 containsAll 的变体,以及 hamcrest 软件包提供的其他一些变体。任何人都可以指出我正确的方向吗?还是我必须编写自定义匹配器?

采纳答案by Hans-Peter St?rr

The shortest way I've come up with is two statements:

我想出的最短方法是两个陈述:

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

But you can probably also do:

但你也可以这样做:

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

depending on the implementations of the maps.

取决于地图的实现。

UPDATE: actually there is one statement that works independently of the collection types:

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

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

回答by Alexey Tigarev

Sometimes Map.equals()is enough. But sometimes you don't know the types of Maps is returned by code under tests, so you don't know if .equals()will properly compare that map of unknown type returned by code with map constructed by you. Or you don't want to bind your code with such tests.

有时Map.equals()就够了。但是有时您不知道Map被测代码返回的s类型,因此您不知道是否.equals()会将代码返回的未知类型的映射与您构建的映射正确比较。或者您不想将您的代码与此类测试绑定。

Additionally, constructing a map separately to compare the result with it is IMHO not very elegant:

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

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));

I prefer using machers:

我更喜欢使用 machers:

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))
));

I have to define hasSize()myself:

我必须定义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");
        }
    };
}

And there is another variant of hasEntry()that takes matchers as parameters instead of exact values of key and value. This can be useful in case you need something other than equality testing of every key and value.

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

回答by Huuu

I favor using Guava ImmutableMap. They support Map.equals()and are easy to construct. The only trick is to explicitly specify type parameters, since hamcrest will assume the ImmutableMaptype.

我喜欢使用Guava ImmutableMap。它们支持Map.equals()并且易于构建。唯一的技巧是显式指定类型参数,因为 hamcrest 将假定ImmutableMap类型。

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

回答by JeanValjean

Another option available now is to use the Cirneco extensionfor Hamcrest. It has hasSameKeySet()(as well as other matchers for Guava "collections"). According to your example, it will be:

现在可用的另一个选项是使用Hamcrest的Cirneco 扩展。它有hasSameKeySet()(以及其他番石榴“集合”的匹配器)。根据您的示例,它将是:

assertThat(affA, hasSameKeySet(affB));

You can use the following dependency for a JDK7-based project:

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

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

or the following if you are using JDK8 or superior:

或者如果您使用的是 JDK8 或更高版本,则执行以下操作:

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

回答by ZPalazov

Hamcrest now has a Matcherfor size collection.

Hamcrest 现在有一个Matcher尺码系列。

org.hamcrest.collection.IsCollectionWithSize

org.hamcrest.collection.IsCollectionWithSize

回答by Bryan Correll

This works like a charm and doesn't require two assertions like the accepted answer.

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

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

回答by Andrii Karaivanskyi

If you need to compare a set of results with expectations and if you choose to use assertjlibrary, you can do this:

如果您需要将一组结果与预期进行比较,并且您选择使用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);

Note that containsAllEntriesOfdoes not compare maps for equality. If your production code returns actually a Map<K, V>you may want to add a check for keys assertThat(results).containsOnlyKeys((K[]) expectations.keySet().toArray());

请注意,containsAllEntriesOf不会比较地图的相等性。如果您的生产代码实际上返回 aMap<K, V>您可能需要添加对密钥的检查assertThat(results).containsOnlyKeys((K[]) expectations.keySet().toArray());

回答by Gabriel Stoenescu

A quite simple way is to use a utility method from Guava's com.google.common.collect.Maps class.

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

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