82 votes

Comment tester avec JUnit que deux List<E> contiennent les mêmes éléments dans le même ordre ?

Contexte

J'écris un simple JUnit test pour le MyObject classe.

A MyObject peut être créé à partir d'une méthode d'usine statique qui prend un varargue de Chaîne de caractères .

MyObject.ofComponents("Uno", "Dos", "Tres");

À tout moment au cours de l'existence de MyObject les clients peuvent consulter les paramètres qui l'ont créé sous la forme d'un fichier de type Liste<E> par le biais de la .getComponents() método.

myObject.ofComponents(); // -> List<String>: { "Uno", "Dos", "Tres" }

En d'autres termes, un MyObject se souvient et expose la liste des paramètres qui l'ont fait naître. Plus de détails sur ce contrat :

  • L'ordre de getComponents sera le même que celui choisi pour la création de l'objet
  • Duplicate subsequent Chaîne de caractères les composants sont autorisés et conservés afin
  • Comportement sur null n'est pas définie (l'autre code ne garantit aucune null arrive à l'usine)
  • Il n'y a aucun moyen de modifier la liste des composants après l'instanciation de l'objet.

J'écris un test simple qui crée un MyObject à partir d'une liste de Chaîne de caractères et vérifie qu'il peut retourner la même liste via .getComponents() . Je le fais immédiatement, mais cela est censé se produire à distance dans un chemin de code réaliste. .

Code

Voici ma tentative :


List<String> argumentComponents = Lists.newArrayList("One", "Two", "Three");
List<String> returnedComponents =
    MyObject.ofComponents(
        argumentComponents.toArray(new String[argumentComponents.size()]))
        .getComponents();
assertTrue(Iterables.elementsEqual(argumentComponents, returnedComponents));

Question

  • Est Google Guava Iterables.elementsEqual() la meilleure façon, à condition d'avoir la bibliothèque dans mon chemin de construction, de comparer ces deux listes ? C'est une question qui me tourmente : dois-je utiliser cette méthode d'aide qui passe au-dessus d'un fichier de données ? Iterable<E> vérifier la taille et ensuite itérer en courant .equals() ou toute autre méthode suggérée par une recherche sur Internet ? Quelle est la méthode canonique pour comparer des listes de tests unitaires ?

Informations facultatives que j'aimerais obtenir

  • Le test de la méthode est-il conçu de manière raisonnable ? Je ne suis pas un expert en JUnit !
  • Est .toArray() la meilleure façon de convertir un Liste<E> à un varargs de E ?

17 votes

+1 pour la question bien structurée.

1 votes

Hamcrest a IsIterableContainingInOrder qui est conçu exactement pour les tests, contrairement à Iterables . L'utilisation de Hamcrest donnera de bons messages en cas d'échec.

0 votes

fest-assert fournit une élégante api...

83voto

assylias Points 102015

Pourquoi ne pas simplement utiliser List#equals ?

assertEquals(argumentComponents, imapPathComponents);

Contrat de List#equals :

deux listes sont définies comme étant égales si elles contiennent les mêmes éléments dans le même ordre.

0 votes

Quel matcheur particulier de Hamcrest ? Je pourrais utiliser des messages d'échec d'assertion précis fournis gratuitement...

1 votes

Comme pour l'absence de bibliothèques externes

0 votes

IMHO ce code semble beaucoup plus clair que celui de Hamcrest IsIterableContainingInOrder.contain() (dont le nom ne reflète pas entièrement son comportement). Donc, si vous avez des collections autres que List<>, il est préférable de les convertir en List et d'utiliser ce code plutôt qu'en array qui est requis par Hamcrest.

58voto

John B Points 17042

Je préfère utiliser Hamcrest car il donne un meilleur résultat en cas d'échec.

Assert.assertThat(listUnderTest, 
       IsIterableContainingInOrder.contains(expectedList.toArray()));

Au lieu de signaler

expected true, got false

il signalera

expected List containing "1, 2, 3, ..." got list containing "4, 6, 2, ..."

IsIterableContainingInOrder.contain

Hamcrest

Selon la Javadoc :

Crée un comparateur pour les Iterables qui correspond lorsqu'un passage unique sur l'Iterable examiné produit une série d'éléments, chacun étant logiquement égal à l'élément correspondant dans les éléments spécifiés. Pour une correspondance positive, l'itérable examiné doit être de la même longueur que le nombre d'éléments spécifiés.

Ainsi, le listUnderTest doivent avoir le même nombre d'éléments et chaque élément doit correspondre aux valeurs attendues dans l'ordre.

1 votes

IsIterableContainingInOrder n'est pas assez strict pour la vérification de l'égalité ?

0 votes

Qu'est-ce que vous voulez dire / qu'est-ce que vous demandez ?

0 votes

La sortie est la même pour Hamcrest que pour les assertions jUnit normales. assertEquals(expected, actual) ; donnera comme résultat : java.lang.AssertionError : expected:<[1, 2]> mais was:<[3, 4]> Je ne pense pas que Hamcrest ait des avantages dans les moyens de la sortie

11voto

DavW Points 440

La méthode equals() de votre implémentation de la liste doit effectuer une comparaison par éléments, donc

assertEquals(argumentComponents, returnedComponents);

est beaucoup plus facile.

10voto

AlexR Points 60796

org.junit.Assert.assertEquals() y org.junit.Assert.assertArrayEquals() faire le travail.

Pour éviter les prochaines questions : Si vous voulez ignorer l'ordre, mettez tous les éléments sur set et ensuite comparez : Assert.assertEquals(new HashSet<String>(one), new HashSet<String>(two))

Si toutefois vous voulez simplement ignorer les doublons tout en préservant l'ordre de votre liste avec LinkedHashSet .

Encore une autre astuce. L'astuce Assert.assertEquals(new HashSet<String>(one), new HashSet<String>(two)) fonctionne bien jusqu'à ce que la comparaison échoue. Dans ce cas, il vous montre un message d'erreur avec des représentations en chaîne de vos ensembles, ce qui peut être déroutant car l'ordre dans l'ensemble n'est presque pas prévisible (du moins pour les objets complexes). Donc, l'astuce que j'ai trouvée est d'envelopper la collection avec sorted set au lieu de HashSet . Vous pouvez utiliser TreeSet avec comparateur personnalisé.

7 votes

L'utilisation d'un HashSet ne préservera pas l'ordre et le les doublons .

5voto

crunchdog Points 3068

Pour une excellente lisibilité du code, Assertions Fest a un bon support pour listes d'affirmation

Donc dans ce cas, quelque chose comme :

Assertions.assertThat(returnedComponents).containsExactly("One", "Two", "Three");

Ou bien transformer la liste attendue en tableau, mais je préfère l'approche ci-dessus car elle est plus claire.

Assertions.assertThat(returnedComponents).containsExactly(argumentComponents.toArray());

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X