JUnit – L’outil idéal des tests unitaires

#java#outil#test

Le principe des tests unitaires

Contrairement à un test d’homologation fonctionnelle qui consiste à valider le fonctionnement de l’applicatif dans sa globalité, l’objectif du test unitaire est de vérifier la validité d’une partie d’un traitement. Certaines méthodologies comme eXtreme Programming (XP) ou Agiles basent leur fondement sur l’élaboration de tests unitaires avant même le démarrage des développements de l’application. Quelle que soit la méthode de développement, il est impératif de réaliser des tests unitaires dans le but de vérifier le bon fonctionnement des programmes, faciliter le débogage et permettre de mettre en œuvre des tests de non régression. Afin d’éviter d’introduire du code de test unitaire au sein même du code de l’applicatif, la majorité des développeurs élabore des programmes de tests qui réalisent des appels à leur code afin de vérifier le fonctionnement. Pour faciliter la création de ces petits programmes, un framework dédié aux tests unitaires est apparu dans le monde Java par sous le nom de JUnit.


Présentation du framework JUnit

Il s’agit d’un logiciel open source, à l’initiative conjointe de Kent Beck (créateur de XP) et Erich Gamma (auteur d’ouvrages sur les Design Patterns), proposant un ensemble d’API et de classes sur lesquelles reposent les classes de test à développer. Il existe principalement trois composants :

  • TestCase : permet de décrire un cas de test
  • TestSuite : permet de décrire un scénario comprenant l’enchaînement d’un ensemble de cas de test ou même d’autres scénarii de tests
  • TestRunner : permet l’exécution proprement dite des composants précédents

Afin de pouvoir mettre en place des cas de test, JUnit propose un ensemble de méthodes qui permettent de valider ou non l’exécution du programme testé dont voici les principales :

  • « assertTrue » vérifie que le résultat retourné est un booléen de valeur « true »
  • « assertNotNull » vérifie que l’objet passé en paramètre n’est pas nul
  • « assertEquals » vérifie l’égalité entre deux types primitifs (string, int, double, etc.) passés en paramètre. Il existe plusieurs signatures de cette méthode en fonction des types de données à comparer et il est possible d’ajouter un delta pour la comparaison de numériques
  • « assertSame » vérifie que les objets passés en paramètre sont identiques
  • « fail » permet de faire échouer le test en affichant un message

Par ailleurs, il existe deux méthodes falcultatives à développer au sein du cas de test « setUP » et « tearDown » qui sont appelées respectivement au début et à la fin de l’exécution de la classe de test. Ceci permet d’initialiser un certain nombre de variables, d’objets ou de ressources (accès à une base de données, ouverture ou création de fichiers, etc.) et aussi de rétablir la situation à la fin d’un test (fermeture de la connexion à une base, fermeture ou suppression d’un fichier, etc.).

L’exécution des cas de tests par l’intermédiaire d’un scénario complet permet de disposer d’une analyse de l’ensemble des méthodes testées. Les résultats peuvent être fournis sous formes textuelles (sortie standard) ou en mode graphique selon le TestRunner utilisé.

JUnit par l’exemple

Voici un programme Java très simple contenant deux méthodes à tester unitairement :

Nous avons écrit une classe de test réalisant un appel de chaque méthode (en général, il est préférable de faire une classe de test pour une classe à tester). Voici le code source du cas de test :

Notre scénario appelle un seul cas de test :

Pour l’exécution de ce cas de test, il est possible d’écrire un programme s’appuyant sur la classe « TestRunner » mais la plupart des outils intègrent JUnit et un simple clic droit permet l’exécution des tests.

Voici un exemple de résultat graphique fourni par l’intermédiaire d’Eclipse pour lequel nous avons volontairement introduit une erreur pour la méthode « euroToFranc » au niveau du calcul :

JUnit à toutes les sauces

Le succès du JUnit dans le cadre des applications Java a permis de voir s’étendre le phénomène à la majeure partie des autres langages de programmation ou technologies dont voici une liste non exhaustive :

Par ailleurs, JUnit est intégré au sein de la plupart des IDE ou autres frameworks de travail. Ainsi, il existe des plug-in pour pouvoir mettre en place des classes de test JUnit et faciliter son utilisation (exécution et analyse) au sein de l’outil de développement Eclipse. De même, Maven ou Ant proposent des modules d’utilisation de JUnit.

Conclusion

Souvent considérée comme une perte de temps inutile au démarrage d’un projet, l’intégration de tests unitaires permet en général de gagner en efficacité sur la durée. Il ne faut évidemment pas tomber dans l’excès en écrivant une classe de test pour chaque méthode de l’applicatif, les fonctions triviales ne doivent pas être l’objet de tests unitaires. L’élaboration de tactiques de tests est nécessaire selon le contexte et la complexité de l’applicatif.

JUnit pour Java et l’ensemble des moutures pour les autres technologies sont particulièrement bien adaptés pour gérer la mise en place de tests unitaires. Le principe de fonctionnement et son utilisation sont assez simples, il n’y a aucune raison de passer à côté d’un tel outil. La majeure partie des équipes de développement s’appuyent sur cet utilitaire pour la confection de cas de tests techniques.

Jean-Sébastien MERCY

Références
1 http://www.junit.org
2 http://junit.sourceforge.net