JUnit 4 comparer les ensembles


102

Comment affirmeriez-vous succinctement l'égalité des Collectionéléments, en particulier a Setdans JUnit 4?



Essayez-vous d'affirmer que deux ensembles sont égaux l'un à l'autre (contiennent les mêmes éléments), ou que deux éléments du même ensemble sont égaux?
Bill the Lizard

J'ai besoin de voir que les éléments de deux sets sont égaux
Eqbal

Réponses:


103

Vous pouvez affirmer que les deux Sets sont égaux l'un à l'autre, ce qui appelle la Set equals()méthode .

public class SimpleTest {

    private Set<String> setA;
    private Set<String> setB;

    @Before
    public void setUp() {
        setA = new HashSet<String>();
        setA.add("Testing...");
        setB = new HashSet<String>();
        setB.add("Testing...");
    }

    @Test
    public void testEqualSets() {
        assertEquals( setA, setB );
    }
}

Cela @Testpassera si les deux Sets sont de la même taille et contiennent les mêmes éléments.


7
Cela n'affiche pas de très bons résultats dans le rapport. Si vos toStrings sont clairement définis, c'est mieux, mais toujours pas bon (Une petite différence peut aboutir à une page de texte)
Bill K

Euh, comment se fait-il que j'obtienne: java.lang.AssertionError: attendu: java.util.Hashtable <{CompanyName = 8PKQ9va3nW8pRWb4SjPF2DvdQDBmlZ, Ric = sZwmXAdYKv, Category = AvrIfd, QuoteId = 43427util j20table Company <4342740} = 8PKQ9va3nW8pRWb4SjPF2DvdQDBmlZ, Ric = sZwmXAdYKv, Category = AvrIfd, QuoteId = 4342740204922826921}>
Giovanni Botta

3
@Giodude Avez-vous equalset hashCodeimplémenté dans la classe que vous stockez dans votre Hashtable?
Bill the Lizard

Comme vous pouvez le voir, ce ne sont que des chaînes et un long ... Je teste Avro pour sérialiser et désérialiser une carte et c'est le résultat. Je pense qu'il doit y avoir quelque chose de louche dans la façon dont les chaînes sont sérialisées et dé-sérialisées qui fait échouer le test, mais je n'arrive pas à trouver le problème.
Giovanni Botta

Cela n'a pas fonctionné pour moi même si je compare deux HashSet <Long>. La réponse @MattFriedman fonctionne réellement pour mon cas d'utilisation.
bluecollarcoder

46

Apache commons à nouveau à la rescousse.

assertTrue(CollectionUtils.isEqualCollection(coll1, coll2));

Fonctionne comme un charme. Je ne sais pas pourquoi mais j'ai trouvé qu'avec les collections, ce qui suit assertEquals(coll1, coll2)ne fonctionne pas toujours. Dans le cas où cela a échoué pour moi, j'avais deux collections soutenues par des ensembles. Ni hamcrest ni junit ne diraient que les collections étaient égales même si je savais avec certitude qu'elles l'étaient. En utilisant CollectionUtils, cela fonctionne parfaitement.


20
C'est en fait trivial, la partie délicate est d'indiquer clairement la différence à l'appelant
Bill K

1
La réponse acceptée est une bonne réponse pour la question originale (test unitaire spécifiquement pour deux ensembles) mais cette réponse avec CollectionUtils est je pense une meilleure réponse pour le cas le plus général. Je n'ai pas pu comparer une collection et un ensemble à moins d'utiliser CollectionUtils.
Jay

16

avec hamcrest :

assertThat(s1, is(s2));

avec une affirmation claire:

assertEquals(s1, s2);

NB: t la méthode equals () de la classe d'ensemble concrète est utilisée


1
Je préfère cette méthode car Hamcrest est livré avec JUnit 4, il n'y a donc pas besoin d'autres bibliothèques.
JRSofty

2
Cela peut ne pas fonctionner lorsque les ensembles ont des types différents.
Hans-Peter Störr

7

Un cas particulièrement intéressant est celui de la comparaison

   java.util.Arrays$ArrayList<[[name,value,type], [name1,value1,type1]]> 

et

   java.util.Collections$UnmodifiableCollection<[[name,value,type], [name1,value1,type1]]>

Jusqu'à présent, la seule solution que je vois est de changer les deux en ensembles

assertEquals(new HashSet<CustomAttribute>(customAttributes), new HashSet<CustomAttribute>(result.getCustomAttributes()));

Ou je pourrais les comparer élément par élément.


En fait, il existe plusieurs solutions à cela présentées dans les autres réponses. Les sets sont un peu malheureux pour cela, de toute façon, car ils ignorent l'ordre. Peut-être ArrayList?
Hans-Peter Störr

4

En tant que méthode supplémentaire basée sur un tableau ... vous pouvez envisager d'utiliser des assertions de tableau non ordonnées dans junitx. Bien que l'exemple Apache CollectionUtils fonctionne, il existe également un ensemble d'extensions d'assertions solides:

Je pense que le

ArrayAssert.assertEquivalenceArrays(new Integer[]{1,2,3}, new Integer[]{1,3,2});

L'approche sera beaucoup plus lisible et déboguable pour vous (toutes les collections prennent en charge toArray (), il devrait donc être assez facile d'utiliser les méthodes ArrayAssert.

Bien sûr, l'inconvénient est que junitx est un fichier jar supplémentaire ou une entrée maven ...

 <dependency org="junit-addons" name="junit-addons" rev="1.4"/>

2

Consultez cet article . Un exemple à partir de là:

@Test  
public void listEquality() {  
    List<Integer> expected = new ArrayList<Integer>();  
    expected.add(5);  

    List<Integer> actual = new ArrayList<Integer>();  
    actual.add(5);  

    assertEquals(expected, actual);  
}  

Lien court mais génial, explique très rapidement ce que vous pouvez faire avec Junit4-
Johannes

1
Le lien est rompu. Avez-vous une chance de trouver une version archivée en ligne ou de résumer son contenu?
pzp

1

Utilisation de Hamcrest:

assertThat( set1, both(everyItem(isIn(set2))).and(containsInAnyOrder(set1)));

Cela fonctionne également lorsque les ensembles ont des types de données différents et signale la différence au lieu de simplement échouer.


2
Quelle est l'importation pour isIn? IntelliJ ne peut pas résoudre l'importation avec un package hamcret.
fabien

0

Si vous souhaitez vérifier si une liste ou un ensemble contient un ensemble de valeurs spécifiques (au lieu de le comparer avec une collection déjà existante), la méthode toString des collections est souvent pratique:

String[] actualResult = calltestedmethod();
assertEquals("[foo, bar]", Arrays.asList(actualResult).toString());

List otherResult = callothertestedmethod();
assertEquals("[42, mice]", otherResult.toString());

C'est un peu plus court que de commencer par construire la collection attendue et de la comparer avec la collection réelle, et plus facile à écrire et à corriger.

(Certes, ce n'est pas une méthode particulièrement propre, et ne peut pas distinguer un élément "foo, bar" de deux éléments "foo" et "bar". Mais en pratique, je pense qu'il est le plus important qu'il soit facile et rapide d'écrire des tests , sinon de nombreux développeurs ne le feront pas sans être pressés.)


Cela rend le résultat de votre test unitaire dépendant de l'implémentation de toString from list. S'ils décident de changer le formatage, le test unitaire ne fonctionnera plus. Je ne considérerais pas cela comme sûr.
Laurens Op 't Zandt

@ LaurensOp'tZandt Vous voulez dire qu'Oracle change le format de Collection.toList ()? Cela n'arrivera certainement pas. Vous avez cependant raison, ce n'est pas particulièrement propre. Mais en pratique, j'ai l'impression qu'il est le plus important qu'il soit très facile d'écrire des tests.
Hans-Peter Störr

Je suis d'accord, je pense que la méthode toString ne sera probablement pas un hasard. Donc, probablement, cela continuera à fonctionner. Je voulais juste souligner que ce n'est pas une manière très propre. Mais en effet, c'est très facile. Un problème qui se pose est lors de la comparaison des ensembles. Puisque leur commande n'est pas garantie.
Laurens Op 't Zandt

0

J'aime la solution de Hans-Peter Störr ... Mais je pense qu'elle n'est pas tout à fait correcte. containsInAnyOrderN'accepte malheureusement pas un Collectiondes objets à comparer. Il faut donc que ce soit un Collectionde Matchers:

assertThat(set1, containsInAnyOrder(set2.stream().map(IsEqual::equalTo).collect(toList())))

Les importations sont:

import static java.util.stream.Collectors.toList;
import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.junit.Assert.assertThat;
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.