Hamcrest vergleicht Sammlungen


114

Ich versuche 2 Listen zu vergleichen:

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

Aber Idee

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)

Wie soll ich es schreiben?

Antworten:


161

Wenn Sie behaupten möchten, dass die beiden Listen identisch sind, erschweren Sie Hamcrest nicht:

assertEquals(expectedList, actual.getList());

Wenn Sie wirklich einen auftragsunabhängigen Vergleich durchführen containsInAnyOrdermöchten , können Sie die varargs-Methode aufrufen und Werte direkt angeben:

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

(Unter der Annahme , dass Ihre Liste ist String, und nicht Agent, für dieses Beispiel.)

Wenn Sie wirklich dieselbe Methode mit dem Inhalt von a aufrufen möchten List:

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

Ohne dies rufen Sie die Methode mit einem einzelnen Argument auf und erstellen eine Matcher, die erwartet, dass sie mit einer übereinstimmt, Iterablebei der jedes Element eine ist List. Dies kann nicht verwendet werden, um a zu entsprechen List.

Das heißt, Sie können a nicht List<Agent>mit a Matcher<Iterable<List<Agent>>abgleichen, was Ihr Code versucht.


+1 für "Wenn Sie wirklich dieselbe Methode mit dem Inhalt einer Liste aufrufen möchten". Leider konnte ich das selbst nicht lösen. Insbesondere, dass es einen Konstruktor gibt, der eine Sammlung aufnimmt.
Eyad Ebrahim

3
@ Tim Nicht ganz; containsInAnyOrdererfordert, dass alle Elemente vorhanden sind, damit die erste Behauptung fehlschlägt. Sehen Sie, hasItemswenn Sie überprüfen möchten , dass zumindest diese Elemente vorhanden sind.
Joe

4
Wenn Sie includesInAnyOrder verwenden, sollten Sie zuerst sicherstellen, dass beide Listen dieselbe Größe haben ... Wenn actual.getList()dies "item1", "item3", "item2"der Fall ist, besteht der Test und Sie möchten möglicherweise sicherstellen, dass er nur die aufgelisteten Elemente enthält ... In diesem Fall können Sie verwenden assertThat(actual.getList().size(), equalTo(2));Auf diese Weise stellen Sie vor dem includesInAnyOrder sicher, dass beide Listen den gleichen Inhalt haben.
Martin

1
@ Martin du denkst an hasItems. Die zusätzliche Prüfung ist hier nicht erforderlich. Siehe den Kommentar zu Tim oben und auch Wie unterscheiden sich Hamcrests hasItems, enthält und enthältInAnyOrder?
Joe

1
Kotlin-Benutzer : Vergessen Sie nicht, den Spread-Operator ( *expectedList.toTypedArray()) hinzuzufügen, wenn Sie ein Array als varargs übergeben!
James Bowman

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

Kürzere Version von @ Joes Antwort ohne redundante Parameter.


28

Zur Ergänzung von @ Joes Antwort:

Hamcrest bietet Ihnen drei Hauptmethoden, um eine Liste abzugleichen:

contains Überprüft, ob alle Elemente übereinstimmen, und zählt die Reihenfolge. Wenn die Liste mehr oder weniger Elemente enthält, schlägt dies fehl

containsInAnyOrder Überprüft, ob alle Elemente übereinstimmen, und es spielt keine Rolle, in welcher Reihenfolge die Liste mehr oder weniger Elemente enthält, schlägt fehl

hasItems Überprüft nur die angegebenen Objekte, es spielt keine Rolle, ob die Liste mehr enthält

hasItem Überprüft nur ein Objekt, es spielt keine Rolle, ob die Liste mehr enthält

Alle von ihnen können eine Liste von Objekten erhalten und eine equalsVergleichsmethode verwenden oder mit anderen Matchern wie @borjab gemischt werden, die erwähnt werden:

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


Ein bisschen spät zur Party, aber danke für die Beschreibung der Unterschiede zwischen den einzelnen Methoden.
Marcos de Andrade

Gute Entscheidung für den Fall, dass Listenelemente nicht primitiv sind.
Stanislav Tsepa

Gibt es einen typsicheren Weg, dies zu tun?
andresp

15

Bei vorhandenen Hamcrest-Bibliotheken (ab Version 2.0.0.0) müssen Sie die Collection.toArray () -Methode für Ihre Sammlung verwenden, um den IncludeInAnyOrder Matcher zu verwenden. Weitaus schöner wäre es, dies als separate Methode zu org.hamcrest.Matchers hinzuzufügen:

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

Tatsächlich habe ich diese Methode zu meiner benutzerdefinierten Testbibliothek hinzugefügt und sie verwendet, um die Lesbarkeit meiner Testfälle zu verbessern (aufgrund der geringeren Ausführlichkeit).


2
Schön, ich werde diesen Helfer benutzen. Die Assert-Nachricht hier ist informativer: Sie benennt die fehlenden Elemente einzeln, nicht nur: Die Liste sollte elem1, elem2, .. elem99 sein, aber ich habe elem1, elem2, ..., elem98 - viel Glück den Vermissten finden.
Pihentagy

3

Stellen Sie sicher, dass die Objects in Ihrer Liste darauf equals()definiert sind. Dann

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

funktioniert.


1

Für die Liste der Objekte benötigen Sie möglicherweise Folgendes:

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

Verwenden Sie includesInAnyOrder, wenn Sie die Reihenfolge der Objekte nicht überprüfen möchten.

PS Jede Hilfe, um die Warnung zu vermeiden, die unterdrückt wird, wird sehr geschätzt.


-3

Um zwei Listen mit der Reihenfolge zu vergleichen, verwenden Sie:

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

Dies beantwortet die Frage nicht.
Kamczak

Das tut es teilweise.
Rvazquezglez

@rvazquezglez Was meinst du? Warum sagst du das? Das Ergebnis der Methode stimmt mit meiner Umgebung überein.
Niaomingjian

@niaomingjian Der Code überprüft, ob das Element actualListdie Elemente im containsMatcher enthält. Dies schlägt fehl, wenn die Elemente nicht in derselben Reihenfolge vorliegen, und schlägt auch fehl, wenn es mehr Elemente enthält oder eines fehlt.
Rvazquezglez

@rvazquezglez Der Zweck des Codes besteht also darin, die genaue Gleichheit (gleiche Längen, Werte und Reihenfolge) in zwei Listen zu untersuchen, oder?
Niaomingjian
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.