2010-03-24 5 views
38

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

Мой текущий догадка:

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

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

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

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

+0

Я также попробовал 'containsAll' и др. Некоторое время назад это выглядело неэффективно - видимо, hamcrest немного ненадежен :-( –

+7

Есть ли причина, по которой вы не можете использовать '.equals()' реализации карты? –

+3

Ah - I hadn 't понял, что коллекции делают правильные сравнения .equals(). Всегда ли это было так? Это облегчает жизнь! Спасибо! –

ответ

41

Самый короткий путь я придумал два заявления:

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()))); 
+0

Что не так с .equals()? – Taras

+3

@Taras: отчетность менее полезна с' .equals() ' –

33

Иногда 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

Вместо использования собственного метода 'hasSize' вы должны использовать' org.hamcrest.collection .IsMapWithSize.aMapWithSize (Matcher ) ' – Eric

2

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

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

Еще один доступный вариант - использовать Cirneco extension для 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> 
+0

Не так ли просто сравнить ключи, но не значения? Вопрос также хотел сравнить значения. –

+0

@ Dr.Hans-PeterStörr Нет, вопрос показывает, что сопоставляются наборы записей – JeanValjean

0

У Hamcrest теперь есть размер Matcher.

org.hamcrest.collection.IsCollectionWithSize

+2

Это не отвечает на исходный вопрос. – Guenther

0

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

assertThat(actualData.entrySet().toArray(), 
    arrayContainingInAnyOrder(expectedData.entrySet().toArray())); 
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());

Смежные вопросы