2010-03-24 16 views
38

Chciałbym użyć hamcrest, aby potwierdzić, że dwie mapy są równe, tj. Mają ten sam zestaw kluczy wskazujących te same wartości.Równość map za pomocą Hamcrest'a

Mój obecny najlepszy przypuszczenie:

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

co daje:

Metoda assertThat (T, Matcher) w rodzaju Assert nie dotyczy argumentów (Set>, Matcher> >>)

Sprawdziłem również odmiany containsAll i niektóre inne dostarczane przez pakiety hamcrest. Czy ktoś może wskazać mi właściwy kierunek? Czy muszę napisać niestandardowy matcher?

+0

Próbowałem również 'containsAll' et al. jakiś czas temu i wydawało się, że nie działa - najwyraźniej hamcrest jest jeszcze trochę niewiarygodny :-( –

+7

Czy istnieje powód, dla którego nie można użyć '.equals()' z implementacji mapy? –

+3

Ah - I hadn nie zdawałem sobie sprawy, że kolekcje robią poprawne porównania .equals() Czy zawsze tak było? To znacznie ułatwia życie! Dziękuję! –

Odpowiedz

41

Najkrótsza droga mam wymyślić to dwa oświadczenia:

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

Ale prawdopodobnie można również zrobić:

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

zależności od implementacji mapach.

UPDATE: rzeczywiście istnieje jeden rachunek, który działa niezależnie od rodzaju kolekcji:

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

Co jest nie tak z .equals()? – Taras

+3

@Taras: raportowanie jest mniej pomocne z' .equals() ' –

33

Czasami wystarczy Map.equals(). Ale czasami nie wiesz, że typy kodu są testowane, więc nie wiesz, czy .equals() poprawnie porówna tę mapę nieznanego typu zwróconą przez kod z mapą stworzoną przez ciebie. Lub nie chcesz wiązać swojego kodu z takimi testami.

Dodatkowo budowy mapy oddzielnie porównać wynik z niej jest IMHO niezbyt elegancki:

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

Wolę wykorzystaniem 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)) 
)); 

muszę zdefiniować hasSize() sobie:

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

I istnieje inny wariant hasEntry(), który przyjmuje parametry dopasowania jako parametry zamiast dokładnych wartości klucza i wartości. Może to być przydatne, jeśli potrzebujesz czegoś innego niż testowanie równości każdego klucza i wartości.

+2

Zamiast używać własnej metody 'hasSize', powinieneś użyć,' org.hamcrest.collection .IsMapWithSize.aMapWithSize (Matcher ) ' – Eric

2

jestem za użyciem Guava ImmutableMap. Wspierają one Map.equals() i są łatwe do skonstruowania. Jedyną sztuczką jest jawne określenie parametrów, ponieważ hamcrest przyjmuje typ ImmutableMap.

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

Inną opcją dostępną teraz jest użycie Cirneco extension dla Hamcrest. Ma hasSameKeySet() (a także inne odpowiedniki dla "kolekcji" Guawy). Według swoim przykładzie będzie to:

assertThat(affA, hasSameKeySet(affB)); 

można wykorzystywać następujące zależności dla projektu o JDK7 opartym:

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

lub kolejny, jeśli używasz JDK8 lub superior:

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

Czy to nie wystarczy porównać klucze, ale nie wartości? Pytanie chciało również porównać wartości: –

+0

@ Dr.Hans-PeterStörr Nie, pytanie pokazuje, że zestawy wpisów są porównywane – JeanValjean

0

Firma Hamcrest ma teraz kolekcję rozmiarów Matcher.

org.hamcrest.collection.IsCollectionWithSize

+2

To nie odpowiada na pierwotne pytanie. – Guenther

0

To działa jak urok i nie wymaga dwóch twierdzeń jak zaakceptowanej odpowiedzi.

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

Jeśli chcesz porównać zestaw wyników z oczekiwaniami, a jeśli zdecydujesz się skorzystać assertj bibliotekę, można to zrobić:

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

Zauważ, że containsAllEntriesOf nie porównuje mapy dla równości. Jeśli twój kod produkcyjny faktycznie zwraca wartość Map<K, V>, możesz chcieć dodać klucz do sprawdzania kluczy: assertThat(results).containsOnlyKeys((K[]) expectations.keySet().toArray());

Powiązane problemy