Подтвердить что ты не робот

Равномерность карты с использованием Hamcrest

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

Мое последнее предположение:

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

который дает:

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

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

4b9b3361

Ответ 1

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

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

Но вы, вероятно, также можете сделать:

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

в зависимости от реализаций карт.

UPDATE: на самом деле существует один оператор, который работает независимо от типов коллекции:

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

Ответ 2

Иногда Map.equals() достаточно. Но иногда вы не знаете, что типы Map возвращаются кодом под тестами, поэтому вы не знаете, будет ли .equals() правильно сравнивать карту неизвестного типа, возвращаемую кодом с построенной вами картой. Или вы не хотите связывать свой код с такими тестами.

Кроме того, построение карты отдельно для сравнения результата с ней является IMHO не очень элегантным:

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(), который принимает сопоставления как параметры вместо точных значений ключа и значения. Это может быть полезно, если вам нужно что-то другое, кроме проверки равенства каждого ключа и значения.

Ответ 3

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

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

Ответ 4

Еще один доступный вариант - использовать расширение Cirneco для Hamcrest. Он имеет hasSameKeySet() (а также другие матчи для коллекций Guava). Согласно вашему примеру, это будет:

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>

Ответ 5

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

org.hamcrest.collection.IsCollectionWithSize

Ответ 6

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

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

Ответ 7

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