Tutoriel JUnit 4 : annotations, Assert, et Hamcrest

JUnit est un framework très utilisé, destiné aux tests (unitaires, non régressions…). La version 4 apporte notamment les annotations grâce à Java 1.5, ce qui le rend beaucoup plus agréable à utiliser.

Ces tests pourront être réutilisés, afin de vérifier que le comportement de l’application est toujours celui attendu. D’autre part, vous pourrez tester votre code sans avoir à utiliser l’IHM, et gagner ainsi en temps de développement.

Le but de cet article est de vous présenter les annotations pour mettre en place les tests, les assertions permettant de vérifier les résultats obtenus, ainsi que l’utilisation d’Hamcrest pour aller plus loin.

I – Avant de se lancer

Pré requis :

  • utiliser JUnit 4.11 minimum. Lors de la rédaction de cet article, la dernière version était la 4.12
  • utiliser un projet en Java 1.5 minimum (les annotations n’étant pas gérées avant)

Installation de JUnit

Afin de gérer simplement vos dépendances, je vous conseille d’utiliser Maven. Ainsi, il vous suffit d’ajouter aux dépendances du POM :

Attention : veillez à utiliser la version 4.11 minimum ! Avant celle-ci, afin d’utiliser la dernière bibliothèque Hamcrest, il fallait gérer individuellement les dépendance de JUnit, exclure la version d’Hamcrest ajoutée depuis JUnit 4, puis remettre la dernière version d’Hamcrest, et ajouter JMock… Ce qui donnait ceci :

Toutefois, si vous préférez utiliser le JAR, vous le trouverez ici.


fleche_haut_gris
Haut de page

Conventions :

Afin de mener sereinement vos tests, et de ne pas les commiter par erreur, je vous conseille d’utiliser un package différent. Par exemple : scr/test/java/monPackage/MaClasseTest.java.

Par convention, toutes les Class de test se terminent par *Test. Le nommage des méthodes n’est plus soumis à l’obligation d’être préfixé par le mot clef test* depuis cette version 4. Précédemment, ces mots clefs servaient à indiquer à JUnit les méthodes devant être appelées, et les Class sur lesquelles utiliser l’introspection.

Les méthodes utilisées pour les tests doivent être indépendantes les unes des autres. Elles ne prendront pas de paramètres, et ne renverront rien. Si un test a besoin de données, les annotations seront vos amies !


fleche_haut_gris
Haut de page

Comment lancer les tests ?

Pour lancer vos tests, vous avez deux possibilités :

  • lancer tous les tests de la Class : dans ce cas, clic droit n’importe où dans la Class => Run As => JUnit test (ou Alt + Shift + X, puis T)
  • lancer un seul test : sélectionner le nom de la méthode, clic droit n’importe où dans la Class => Run As => JUnit test (ou Alt + Shift + X, puis T)

La méthodologie de test sera toujours la même :

  • préparer les données pour la Class ou la méthode (facultatif)
  • exécuter le test
  • vérifier les résultats
  • nettoyer (facultatif)


fleche_haut_gris
Haut de page

Class utilisées

Pour reproduire les exemples de cet article, vous pouvez utiliser la Class ConsoleOut.java suivante :

Maintenant que le décor est planté, nous pouvons entrer dans le vif du sujet !


fleche_haut_gris
Haut de page

II – Les annotations

@Rule (4.7)

Permet de définir une règle pour l’ensemble des tests. Par exemple, pour définir un timeout global :

Avec cette déclaration, JUnit octroiera 10 secondes maximum à  chaque test. Autre exemple, avec l’obligation d’utiliser notre Class ConsoleOut :

OneRule.java :

Ici, la sortie console sera :

Où suis-je ? Test regle unique

Une seule étape passée.

Si vous avez besoin de plusieurs règles, il faut utiliser une RuleChain (4.10) :

Cette fois, nous aurons :

Où suis-je ? 1ere regle

Où suis-je ? 2e regle

Où suis-je ? 3e regle

Exemple terminé !

Comme vous le remarquez, les règles sont traitées dans l’ordre inverse d’écriture. En fait, on part de l’extérieur pour aller vers l’intérieur.


fleche_haut_gris
Haut de page

@Test

Il s’agit de l’annotation principale de JUnit. Elle permet d’indiquer la méthode à tester, et peut être utilisée sans paramètres.

Si les tests le nécessitent, vous pouvez ajouter jusqu’à deux paramètres :

  • timeout : permet d’ajouter un timeout au bout duquel le test échouera. Par exemple, si je reprends le même code qu’au dessus, mais en ajoutant un timer :

Mon test échouera, car il ne se sera pas terminé en moins de 5 secondes.

  • expected : permet de préciser que l’on attend une levée d’exception. Si aucune erreur ne se produit pas, le test sera considéré comme fail :

Ce code ne fonctionne pas, mais l’annotation expected précise que l’on attend un échec… Ce fail est donc une réussite !

Enfin, en cumulant les deux conditions :

Ici, la méthode avait 5 secondes pour terminer avec une ArithmeticException : même en attendant 3 secondes, il n’en fallait pas 2 de plus pour produire l’erreur attendue. Le test est donc considéré comme réussi.

@Ignore

Comme son nom l’indique, cette annotation permet d’ignorer une méthode dans le cas où on exécuterait la totalité des tests de la Class. Un paramètre de type String peut être ajouté, et servira uniquement à indiquer la raison du retrait :

@Before

Permet de préparer des données nécessaires au déroulement des tests suivants. Cette méthode sera appelée systématiquement avant chaque test, et ne prendra jamais de paramètres. Elle remplace la méthode setup() des versions de JUnit antérieures à la 4. Utile pour, par exemple, instancier des variables de Class ou récupérer des données en base :

Dans cet exemple, “s” ne sert à rien. Mais il pourrait être utilisé pour vérifier les résultats récupérés, comme nous le verrons plus loin.

@After

Cette méthode sera appelée systématiquement après chaque test, et ne prendra jamais de paramètres. Elle remplace la méthode tearDown() des versions de JUnit antérieures à la 4. Utile pour, par exemple, ré initialiser des variables de Class ou récupérer des données en base :

@BeforeClass

Cette méthode sera appelée une seule fois, avant les tests, et ne prendra jamais de paramètres. Elle sera utile pour, par exemple, récupérer des données en base utiles pour le déroulement des tests :

@AfterClass

Cette méthode sera appelée une seule fois, après les tests, et ne prendra jamais de paramètres. Elle sera utile pour, par exemple, effectuer un RollBack des modifications effectuées en base.


fleche_haut_gris
Haut de page

III – Les Assertions

Maintenant que nous avons vu comment initialiser et traiter les données, il serait intéressant de vérifier le résultat obtenu. Bien sûr, le but étant que ces comparaisons se fassent de façon automatique. Pour ce faire, il faut utiliser les Assertions, ce qui signifie affirmation. De nombreuses méthodes surchargées permettent d’effectuer une comparaison entre l’attendu et le résultat. Elles peuvent avoir au choix :

  • 2 paramètres : le premier sera le résultat attendu, le second le résultat obtenu
  • 3 paramètres : le premier sera un message à afficher, le deuxième le résultat attendu, et le troisième le résultat obtenu

Attention au niveau de l’import du package :

Si vous désirez utilisez directement votre assertion, il faut l’importer :

Cet import est à privilégier pour des raisons de performances et de lisibilité. Sinon, en important le package classique, vous écrirez :

Vous pouvez utiliser les méthodes des comparaisons suivantes :

  • assertArrayEquals() : permet de comparer des Arrays, de primitifs ou d’objets.
  • assertEquals() : permet de comparer des primitifs ou des Objects. Pour les Double, il faut désormais passer en paramètre un Delta autorisé entre l’attendu et le résultat.
  • assertFalse() : le résultat doit être égal à false.
  • assertNotNull() : l’Object ne doit pas être null.
  • assertNotSame() : les 2 Objects passés en paramètres ne doivent pas avoir la même référence.
  • assertNull() : l’Object doit être null.
  • assertSame() : les 2 Objects doivent avoir la même référence.
  • assertThat() : permet d’effectuer une comparaison à l’aide d’autres frameworks, cf plus bas.
  • assertTrue() : le résultat doit être égal à true.
  • fail() : fait échouer le test, et peut prendre en paramètre un message pour la console. Utile pour les conditions.


fleche_haut_gris
Haut de page

Le cas particulier de assertThat() (4.4)

Cette méthode permet de vérifier plus naturellement une condition. Plutôt que d’écrire “vérifier que égale [attendu], [resultat]”, il apparaît beaucoup plus logique d’écrire “vérifier que [attendu] correspond à [monTest]” :

assertThat([attendu], [monTest]);

Pour la condition, en plus des méthodes de comparaison de JUnit, il est également possible d’utiliser Hamcrest, JSON, ou d’autres !

Cela donne donc une méthode à la fois puissante et flexible.

Depuis la version 4, JUnit intègre le projet Hamcrest. Si vous ne le connaissez pas, il s’agit d’un framework permettant d’écrire ses propres règles de validation.

Hamcrest apporte 12 méthodes très simples à utiliser :

allOf()

Nécessite que toutes les conditions passées en paramètre soient vérifiées :

assertThat(“blabla”, is(allOf(notNullValue(), instanceOf(String.class), equalTo(“blabla”))));

any()

Vérifie que l’objet est une instance de la Class passée en paramètre. Fonctionne avec les Class mères :

assertThat(“blabla”, is(any(String.class)));

assertThat(“blabla”, is(any(Object.class)));

anyOf()

Nécessite qu’au moins une condition soit vérifiée :

assertThat(“blabla”, is(anyOf(equalTo(“lorem”), instanceOf(String.class))));

anything()

Renvoie toujours true… Aucune idée des cas où elle serait utile !

assertThat(“blabla”, is(anything()));

Cette méthode appelle en fait une autre méthode très simple :

describedAs()

Permet de faire un override de la description d’un Matcher :


fleche_haut_gris
Haut de page

equalTo()

Simple vérification d’égalité :

instanceOf()

Vérifie que l’objet est bien de l’instance passée en paramètre. Fonctionne avec les Class mères :

is()

Il aurait fallu commencer par cette méthode, mais le chaos se serait installé dans le classement, entrainant inéluctablement la fin du monde ordonné… Vérifie que la condition est à true.

not()

Vérifie l’inverse de is() :

notNullValue()

Vérifie la non nullité de l’objet :

nullValue()

Vérifie la nullité de l’objet :

sameInstance()

Vérifie la référence de deux objets, afin de vérifier s’il s’agit de la même instance :


fleche_haut_gris
Haut de page

Pour conclure…

J’espère que cet article vous aura permis d’en apprendre un peu plus sur les tests avec JUnit dans sa dernière version, ainsi que sur Hamcrest.

Si tel est le cas, n’hésitez pas à le partager avec un des boutons ci-dessous !

Previous Post

Comments are closed.