Hamcrest porównuje kolekcje


114

Próbuję porównać 2 listy:

assertThat(actual.getList(), is(Matchers.containsInAnyOrder(expectedList)));

Ale pomysł

java: no suitable method found for assertThat(java.util.List<Agent>,org.hamcrest.Matcher<java.lang.Iterable<? extends model.Agents>>)
method org.junit.Assert.<T>assertThat(T,org.hamcrest.Matcher<T>) is not applicable
  (no instance(s) of type variable(s) T exist so that argument type org.hamcrest.Matcher<java.lang.Iterable<? extends model.Agents>> conforms to formal parameter type org.hamcrest.Matcher<T>)
method org.junit.Assert.<T>assertThat(java.lang.String,T,org.hamcrest.Matcher<T>) is not applicable
  (cannot instantiate from arguments because actual and formal argument lists differ in length)

Jak mam to napisać?

Odpowiedzi:


161

Jeśli chcesz zapewnić, że te dwie listy są identyczne, nie komplikuj rzeczy z Hamcrestem:

assertEquals(expectedList, actual.getList());

Jeśli naprawdę zamierzasz przeprowadzić porównanie niewrażliwe na kolejność, możesz wywołać containsInAnyOrdermetodę varargs i podać wartości bezpośrednio:

assertThat(actual.getList(), containsInAnyOrder("item1", "item2"));

(Zakładając, że twoja lista to String, a nieAgent w tym przykładzie ).

Jeśli naprawdę chcesz wywołać tę samą metodę z zawartością a List:

assertThat(actual.getList(), containsInAnyOrder(expectedList.toArray(new String[expectedList.size()]));

Bez tego wywołujesz metodę z pojedynczym argumentem i tworzysz element, Matcherktóry oczekuje dopasowania elementu Iterablegdzie każdy element jest List. Nie można tego użyć do dopasowania List.

Oznacza to, że nie możesz dopasować a List<Agent>z a Matcher<Iterable<List<Agent>>, co jest tym, co próbuje twój kod.


+1 dla „Jeśli naprawdę chcesz wywołać tę samą metodę z zawartością listy”. Niestety nie mogłem sam tego rozwiązać. Zwłaszcza, że ​​istnieje konstruktor, który pobiera kolekcję.
Eyad Ebrahim

3
@Tim Niezupełnie; containsInAnyOrderwymaga, aby wszystkie elementy były obecne, aby pierwsze twierdzenie zakończyło się niepowodzeniem. Sprawdź, hasItemsczy chcesz sprawdzić, czy są obecne przynajmniej te elementy.
Joe,

4
Jeśli korzystasz z containsInAnyOrder, powinieneś najpierw upewnić się, że obie listy mają ten sam rozmiar ... Jeśli actual.getList()zdarzy się "item1", "item3", "item2", że zawiera , test przejdzie pomyślnie i być może chcesz się upewnić, że zawiera on tylko wymienione elementy ... W takim przypadku możesz użyć assertThat(actual.getList().size(), equalTo(2));przed zawartością zawieraInAnyOrder, w ten sposób upewniasz się, że obie listy mają taką samą zawartość.
Martin

1
@Martin, o którym myślisz hasItems. Dodatkowa kontrola jest tutaj niepotrzebna. Zobacz komentarz do Tima powyżej, a także Czym różnią się elementy hasItems, zawiera i zawiera w zamówieniu Hamcrest?
Joe

1
Użytkownicy Kotlin : nie zapomnijcie dodać operatora spreadu ( *expectedList.toTypedArray()) podczas przekazywania tablicy jako varargs!
James Bowman,

63
List<Long> actual = Arrays.asList(1L, 2L);
List<Long> expected = Arrays.asList(2L, 1L);
assertThat(actual, containsInAnyOrder(expected.toArray()));

Krótsza wersja odpowiedzi @ Joe bez zbędnych parametrów.


28

Aby uzupełnić odpowiedź @ Joe:

Hamcrest zapewnia trzy główne metody dopasowania listy:

contains Sprawdza dopasowanie wszystkich elementów biorąc pod uwagę kolejność, jeśli lista zawiera mniej lub więcej elementów, zakończy się niepowodzeniem

containsInAnyOrder Sprawdza dopasowanie wszystkich elementów i nie ma znaczenia kolejność, jeśli lista zawiera mniej lub więcej elementów, zakończy się niepowodzeniem

hasItems Sprawdza tylko określone obiekty, nie ma znaczenia, czy lista ma ich więcej

hasItem Sprawdza tylko jeden obiekt, nie ma znaczenia, czy lista ma więcej

Wszystkie z nich mogą otrzymać listę obiektów i użyć equalsmetody do porównania lub mogą być mieszane z innymi dopasowaniami, takimi jak wspomniany @borjab:

assertThat(myList , contains(allOf(hasProperty("id", is(7L)), 
                                   hasProperty("name", is("testName1")),
                                   hasProperty("description", is("testDesc1"))),
                             allOf(hasProperty("id", is(11L)), 
                                   hasProperty("name", is("testName2")),
                                   hasProperty("description", is("testDesc2")))));

http://hamcrest.org/JavaHamcrest/javadoc/1.3/org/hamcrest/Matchers.html#contains (E ...) http://hamcrest.org/JavaHamcrest/javadoc/1.3/org/hamcrest/Matchers.html #containsInAnyOrder (java.util.Collection) http://hamcrest.org/JavaHamcrest/javadoc/1.3/org/hamcrest/Matchers.html#hasItems (T ...)


Trochę za późno na imprezę, ale dzięki za opis różnic między każdą metodą.
Marcos de Andrade,

Świetna decyzja w przypadku, gdy elementy listy nie są typu pierwotnego.
Stanislav Tsepa

Czy jest na to bezpieczny sposób?
andresp

15

Z istniejącymi bibliotekami Hamcrest (od wersji 2.0.0.0) jesteś zmuszony użyć metody Collection.toArray () na swojej kolekcji, aby użyć dopasowującego includeInAnyOrder. O wiele przyjemniej byłoby dodać to jako oddzielną metodę do org.hamcrest.Matchers:

public static <T> org.hamcrest.Matcher<java.lang.Iterable<? extends T>> containsInAnyOrder(Collection<T> items) {
    return org.hamcrest.collection.IsIterableContainingInAnyOrder.<T>containsInAnyOrder((T[]) items.toArray());
}

W rzeczywistości dodałem tę metodę do mojej własnej biblioteki testów i użyłem jej do zwiększenia czytelności moich przypadków testowych (ze względu na mniejszą szczegółowość).


2
Niezły, użyję tego pomocnika. Wiadomość assert jest tutaj bardziej pouczająca: wymienia brakujące elementy pojedynczo, a nie tylko: lista powinna być elem1, elem2, .. elem99, ale otrzymałem elem1, elem2, ..., elem98 - powodzenia znalezienie brakującego.
pihentagy

3

Upewnij się, że zdefiniowano na nich Objects na liście equals(). Następnie

    assertThat(generatedList,is(equalTo(expectedList)));

Pracuje.


1

Aby uzyskać listę obiektów, możesz potrzebować czegoś takiego:

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.allOf;
import static org.hamcrest.beans.HasPropertyWithValue.hasProperty;
import static org.hamcrest.Matchers.is;

@Test
@SuppressWarnings("unchecked")
public void test_returnsList(){

    arrange();
  
    List<MyBean> myList = act();
    
    assertThat(myList , contains(allOf(hasProperty("id",          is(7L)), 
                                       hasProperty("name",        is("testName1")),
                                       hasProperty("description", is("testDesc1"))),
                                 allOf(hasProperty("id",          is(11L)), 
                                       hasProperty("name",        is("testName2")),
                                       hasProperty("description", is("testDesc2")))));
}

Użyj opcji containsInAnyOrder, jeśli nie chcesz sprawdzać kolejności obiektów.

PS Każda pomoc w uniknięciu zniesionego ostrzeżenia będzie naprawdę mile widziana.


-3

Aby porównać dwie listy z zachowaną kolejnością użycia,

assertThat(actualList, contains("item1","item2"));

To nie odpowiada na pytanie.
kamczak

Częściowo tak.
rvazquezglez

@rvazquezglez Co masz na myśli? Dlaczego to mówisz? Wynik tej metody jest odpowiedni w moim środowisku.
niaomingjian

@niaomingjian Kod sprawdza, czy element actualListzawiera elementy wewnątrz elementu containsdopasowującego, co nie powiedzie się, jeśli elementy nie są w tej samej kolejności, a także zakończy się niepowodzeniem, jeśli zawiera więcej elementów lub ich brakuje.
rvazquezglez

@rvazquezglez, więc celem kodu jest sprawdzenie dokładnej równości (tej samej długości, wartości i kolejności) na dwóch listach, prawda?
niaomingjian
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.