Равенство карт с помощью Hamcrest - PullRequest
45 голосов
/ 24 марта 2010

Я хотел бы использовать Hamcrest, чтобы утверждать, что две карты равны, то есть они имеют одинаковый набор ключей, указывающих на одинаковые значения.

Моя лучшая догадка:

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

, что дает:

Метод assertThat (T, Matcher) в типе Assert не применим для аргументов (Set>, Matcher >>>)

Я также посмотрел на варианты containsAll и некоторые другие, предоставляемые пакетами hamcrest. Может кто-то указать мне верное направление? Или я должен написать собственный сопоставитель?

Ответы [ 8 ]

49 голосов
/ 27 августа 2012

Самый короткий способ, которым я придумаю, это два утверждения:

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())));
37 голосов
/ 19 ноября 2011

Иногда Map.equals() достаточно. Но иногда вы не знаете, что типы Map s возвращаются тестируемым кодом, поэтому вы не знаете, будет ли .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));

Я предпочитаю использовать 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))
));

Я должен определить 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 голосов
/ 30 декабря 2015

Другой доступный вариант - использовать расширение Cirneco для Hamcrest. Он имеет 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>
2 голосов
/ 16 апреля 2015

Я предпочитаю использовать Guava ImmutableMap . Они поддерживают Map.equals() и их легко построить. Единственная хитрость заключается в явном указании параметров типа, поскольку hamcrest примет тип ImmutableMap.

assertThat( actualValue,
            Matchers.<Map<String, String>>equalTo( ImmutableMap.of(
                "key1", "value",
                "key2", "other-value"
) ) );
1 голос
/ 03 мая 2018

Довольно простым способом является использование служебного метода из класса com.google.common.collect.Maps, принадлежащего Guava.

assertThat(Maps.difference(map1,map2).areEqual(),is(true));
0 голосов
/ 28 августа 2017

Если вам нужно сравнить набор результатов с ожиданиями и если вы решите использовать библиотеку 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());

0 голосов
/ 20 июня 2017

Это работает как брелок и не требует двух утверждений, таких как принятый ответ.

assertThat( actualData.entrySet().toArray(), 
    arrayContainingInAnyOrder(expectedData.entrySet().toArray()) );
0 голосов
/ 10 сентября 2016

Hamcrest теперь имеет Matcher для коллекции размеров.

org.hamcrest.collection.IsCollectionWithSize

...