Hamcrest Comparer les collections

114

J'essaye de comparer 2 listes:

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

Mais idée

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)

Comment dois-je l'écrire?

xander27
la source

Réponses:

161

Si vous voulez affirmer que les deux listes sont identiques, ne compliquez pas les choses avec Hamcrest:

assertEquals(expectedList, actual.getList());

Si vous avez vraiment l'intention d'effectuer une comparaison insensible à l'ordre, vous pouvez appeler la containsInAnyOrderméthode varargs et fournir des valeurs directement:

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

(En supposant que votre liste est de String, plutôt que Agent, pour cet exemple.)

Si vous voulez vraiment appeler cette même méthode avec le contenu d'un List:

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

Sans cela, vous appelez la méthode avec un seul argument et créez un Matcherqui s'attend à correspondre à un Iterablechaque élément est un List. Cela ne peut pas être utilisé pour correspondre à un List.

Autrement dit, vous ne pouvez pas faire correspondre a List<Agent>avec a Matcher<Iterable<List<Agent>>, ce que votre code tente de faire.

Joe
la source
+1 pour le "Si vous voulez vraiment appeler cette même méthode avec le contenu d'une liste". Malheureusement, je n'ai pas pu résoudre ce problème moi-même. Surtout qu'il existe un constructeur qui prend dans une collection.
Eyad Ebrahim
3
@Tim Pas tout à fait; containsInAnyOrderexige que tous les éléments soient présents, de sorte que la première assertion échouera. Voyez hasItemssi vous voulez vérifier qu'au moins ces éléments sont présents.
Joe
4
Si vous utilisez containsInAnyOrder, vous devez d'abord vous assurer que les deux listes ont la même taille ... S'il actual.getList()arrive à contenir "item1", "item3", "item2", le test passera et vous voudrez peut-être vous assurer qu'il ne contient que les éléments répertoriés ... Dans ce cas, vous pouvez utiliser assertThat(actual.getList().size(), equalTo(2));avant le containsInAnyOrder, vous vous assurez ainsi que les deux listes ont le même contenu.
Martin
1
@Martin auquel vous pensez hasItems. Le contrôle supplémentaire n'est pas nécessaire ici. Voir le commentaire à Tim ci-dessus, et aussi Comment les hasItems, contains et containsInAnyOrder de Hamcrest diffèrent-ils?
Joe
1
Utilisateurs de Kotlin : n'oubliez pas d'ajouter l'opérateur spread ( *expectedList.toTypedArray()) lors du passage d'un tableau en varargs!
James Bowman
63
List<Long> actual = Arrays.asList(1L, 2L);
List<Long> expected = Arrays.asList(2L, 1L);
assertThat(actual, containsInAnyOrder(expected.toArray()));

Version plus courte de la réponse de @ Joe sans paramètres redondants.

Jofsey
la source
28

Pour compléter la réponse de @ Joe:

Hamcrest vous propose trois méthodes principales pour faire correspondre une liste:

contains Vérifie la correspondance de tous les éléments en prenant en compte l'ordre, si la liste a plus ou moins d'éléments, elle échouera

containsInAnyOrder Vérifie la correspondance de tous les éléments et peu importe l'ordre, si la liste contient plus ou moins d'éléments, échouera

hasItems Vérifie uniquement les objets spécifiés, peu importe si la liste en contient plus

hasItem Vérifie un seul objet, peu importe si la liste en contient plus

Tous peuvent recevoir une liste d'objets et utiliser une equalsméthode de comparaison ou peuvent être mélangés avec d'autres correspondants comme @borjab mentionné:

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

rvazquezglez
la source
Un peu tard à la fête, mais merci pour la description des différences entre chaque méthode.
Marcos de Andrade
Excellente décision lorsque les éléments de la liste de cas ne sont pas de type primitif.
Stanislav Tsepa
Existe-t-il un moyen sûr de faire cela?
andresp le
15

Avec les bibliothèques Hamcrest existantes (à partir de la v.2.0.0.0), vous êtes obligé d'utiliser la méthode Collection.toArray () sur votre Collection afin d'utiliser le Matcher containsInAnyOrder. Il serait préférable d'ajouter ceci en tant que méthode distincte à 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());
}

En fait, j'ai fini par ajouter cette méthode à ma bibliothèque de tests personnalisés et l'utiliser pour augmenter la lisibilité de mes cas de test (en raison de moins de verbosité).

yvolk
la source
2
Gentil, je vais utiliser cet assistant. Le message d'assert ici est plus informatif: il nomme les éléments manquants un par un, pas seulement: la liste devrait être elem1, elem2, .. elem99, mais j'ai eu elem1, elem2, ..., elem98 - bonne chance trouver celui qui manque.
pihentagy
3

Assurez-vous que les Objects de votre liste y sont equals()définis. ensuite

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

travaux.

Jim Jarrett
la source
1

Pour la liste des objets, vous aurez peut-être besoin de quelque chose comme ceci:

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

Utilisez containsInAnyOrder si vous ne souhaitez pas vérifier l'ordre des objets.

PS Toute aide pour éviter l'avertissement supprimé sera vraiment appréciée.

Borjab
la source
-3

Pour comparer deux listes avec l'ordre d'utilisation conservé,

assertThat(actualList, contains("item1","item2"));
Shravan Ramamurthy
la source
Cela ne répond pas à la question.
kamczak le
C'est partiellement le cas.
rvazquezglez
@rvazquezglez Que voulez-vous dire? Pourquoi dites vous cela? Le résultat de la méthode est juste dans mon environnement.
niaomingjian
@niaomingjian Le code vérifie que le actualListcontient les éléments à l'intérieur du containsmatcher, cela échouera si les éléments ne sont pas dans le même ordre et échouera également s'il contient plus d'éléments ou s'il en manque un.
rvazquezglez
@rvazquezglez donc le but du code est d'examiner l'égalité exacte (mêmes longueurs, valeurs et ordre) dans deux listes, non?
niaomingjian