Hamcrest confronta le raccolte


114

Sto cercando di confrontare 2 elenchi:

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

Ma idea

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)

Come dovrei scriverlo?

Risposte:


161

Se vuoi affermare che i due elenchi sono identici, non complicare le cose con Hamcrest:

assertEquals(expectedList, actual.getList());

Se intendi davvero eseguire un confronto insensibile all'ordine, puoi chiamare il containsInAnyOrdermetodo varargs e fornire direttamente i valori:

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

(Supponendo che la tua lista sia di String, piuttosto che Agent, per questo esempio.)

Se vuoi davvero chiamare lo stesso metodo con il contenuto di a List:

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

Senza questo, stai chiamando il metodo con un singolo argomento e creando un file Matcherche si aspetta di trovare una corrispondenza in Iterablecui ogni elemento è un List. Non può essere utilizzato per abbinare un file List.

Cioè, non puoi abbinare a List<Agent>con a Matcher<Iterable<List<Agent>>, che è ciò che il tuo codice sta tentando.


+1 per "Se vuoi davvero chiamare lo stesso metodo con il contenuto di una lista". Purtroppo non sono riuscito a risolverlo da solo. Soprattutto che esiste un costruttore che accetta una raccolta.
Eyad Ebrahim

3
@Tim Non proprio; containsInAnyOrderrichiede che tutti gli elementi siano presenti, in modo che la prima affermazione fallisca. Vedi hasItemsse vuoi controllare che almeno quegli elementi siano presenti.
Joe

4
Se usi containsInAnyOrder, dovresti prima assicurarti che entrambi gli elenchi abbiano la stessa dimensione ... Se actual.getList()dovesse contenere "item1", "item3", "item2", il test passerà e forse vuoi assicurarti che contenga solo gli elementi elencati ... In tal caso potresti usare assertThat(actual.getList().size(), equalTo(2));prima di containsInAnyOrder, in questo modo assicurati che entrambi gli elenchi abbiano lo stesso contenuto.
Martin,

1
@ Martin a cui stai pensando hasItems. Il controllo extra non è necessario qui. Vedi il commento a Tim sopra e anche In che modo differiscono hasItems, contains e containsInAnyOrder di Hamcrest?
Joe

1
Utenti Kotlin : non dimenticare di aggiungere l'operatore di diffusione ( *expectedList.toTypedArray()) quando si passa un array come varargs!
James Bowman

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

Versione più breve della risposta di @ Joe senza parametri ridondanti.


28

Per completare la risposta di @ Joe:

Hamcrest ti fornisce tre metodi principali per abbinare un elenco:

contains Controlla la corrispondenza di tutti gli elementi tenendo conto dell'ordine, se l'elenco ha più o meno elementi, fallirà

containsInAnyOrder Controlla la corrispondenza di tutti gli elementi e non importa l'ordine, se l'elenco contiene più o meno elementi, fallirà

hasItems Controlla solo gli oggetti specificati, non importa se l'elenco ne ha di più

hasItem Controlla solo un oggetto, non importa se l'elenco ne ha di più

Tutti possono ricevere un elenco di oggetti e utilizzare il equalsmetodo per il confronto o possono essere combinati con altri abbinamenti come @borjab menzionato:

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


Un po 'tardi per la festa, ma grazie per la descrizione delle differenze tra ogni metodo.
Marcos de Andrade

Ottima decisione nel caso in cui gli elementi dell'elenco non siano di tipo primitivo.
Stanislav Tsepa

Esiste un modo sicuro per farlo?
andresp

15

Con le librerie Hamcrest esistenti (a partire dalla v.2.0.0.0) sei costretto a utilizzare il metodo Collection.toArray () sulla tua raccolta per utilizzare containsInAnyOrder Matcher. Molto più bello sarebbe aggiungerlo come metodo separato a 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());
}

In realtà ho finito per aggiungere questo metodo alla mia libreria di test personalizzata e usarlo per aumentare la leggibilità dei miei casi di test (a causa della minore verbosità).


2
Bello, userò questo aiutante. Il messaggio di asserzione qui è più informativo: nomina gli elementi mancanti uno per uno, non solo: l'elenco dovrebbe essere elem1, elem2, .. elem99, ma ho elem1, elem2, ..., elem98 - buona fortuna trovare quello mancante.
pihentagy

3

Assicurati che Objecti messaggi nella tua lista siano equals()definiti su di essi. Poi

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

lavori.


1

Per l'elenco degli oggetti potresti aver bisogno di qualcosa del genere:

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

Utilizzare containsInAnyOrder se non si desidera controllare l'ordine degli oggetti.

PS Qualsiasi aiuto per evitare l'avvertimento soppresso sarà molto apprezzato.


-3

Per confrontare due elenchi con l'ordine conservato utilizzare,

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

Questo non risponde alla domanda.
kamczak

In parte lo fa.
rvazquezglez

@rvazquezglez Cosa intendi? Perché dici questo? Il risultato del metodo è giusto nel mio ambiente.
niaomingjian

@niaomingjian Il codice sta controllando che actualListcontenga gli elementi all'interno di containsmatcher, che fallirà se gli elementi non sono nello stesso ordine e fallirà anche se contiene più elementi o ne manca uno.
rvazquezglez

@rvazquezglez quindi lo scopo del codice è esaminare l'esatta uguaglianza (stesse lunghezze, valori e ordine) in due elenchi, giusto?
niaomingjian
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.