Test unitaire
Enprogrammation informatique,letest unitaire(ou «T.U.», ou «U.T.» en anglais) est une procédure permettant de vérifier le bon fonctionnement d'une partie précise d'unlogicielou d'une portion d'unprogramme(appelée « unité » ou « module »).
Dans les applications non critiques, l'écriture des tests unitaires a longtemps été considérée comme une tâche secondaire. Cependant, les méthodesExtreme programming(XP) ouTest Driven Development(TDD) ont remis les tests unitaires, appelés « tests du programmeur », au centre de l'activité de programmation.
Origine et histoire
[modifier|modifier le code]Les test unitaires, en tant que principe de tester séparément des parties plus élémentaires d'un logiciel complexe, remonte aux débuts de l'ingéniérie logicielle. En Juin 1956, H.D. Benington présente en effet le projetSAGEau symposium sur les méthodes de programmation avancée organisé par lamarine américaine.L'approche utilisée prévoyait à l'issue de la phase de codage une étape de "tests de paramètres" pour valider la conformité des sous-programmes et composants à leur spécifications, avant de procéder à un "test d'assemblage" de ces composants[1],[2].
En 1964, une approche similaire est décrite pour les logiciels duprogramme Mercury:les unités individuelles développées par différentes organisations étaient soumises à des "tests unitaires" avant d'être intégrées entre elles. En 1969, les méthodologies de tests sont structurées encore davantage, avec des tests unitaires, des tests de composants, et destests d'intégration,dans le but de valider des parties élémentaires du logiciel séparément, puis de vérifier le bon fonctionnement des assemblages progressif en blocs plus larges[3].Des normes publiques adoptées à la fin des années 60, telles que les standards militaires MIL-STD-483[4]et MIL-STD-490 de l'armée américaine contribuent à une large reconnaissance et adoption des tests unitaires au sein de gros projets.
Les tests unitaires étaient alors interactifs[2],ou automatisés[5],utilisant soit des tests programmés ou des outils de capture et répétition automatisés. En 1994Kent Beckdécrit un environnement cadre de test pour le langageSmalltalk,qui deviendraSUnit[6]par la suite[7],[8].En 1997,Kent BeckrencontreErich Gammaavec lequel il créeJUnitqui, par sa popularité, entraînera la création de nombreuxframeworksde tests unitaires, cet ensemble se nommexUnit[9].
À la même époque, ATTOL Unit test est développé, puis utilisé parSextant Avioniqueen 1998[10]
Utilité[11]
[modifier|modifier le code]On écrit un test pour confronter une réalisation à saspécification.Letestdéfinit un critère d'arrêt (état ou sorties à l'issue de l'exécution) et permet de statuer sur le succès ou sur l'échec d'une vérification. Grâce à la spécification, on est en mesure de faire correspondre un état d'entrée donné à un résultat ou à une sortie. Letestpermet de vérifier que la relation d'entrée / sortie donnée par la spécification est bel et bien réalisée.
Trouver les erreurs rapidement
[modifier|modifier le code]La méthode XP préconise d'écrire les tests en même temps, ou même avant la fonction à tester (Test Driven Development). Ceci permet de définir précisément l'interface du module à développer. Les tests sont exécutés durant tout le développement, permettant de visualiser si le code fraîchement écrit correspond au besoin.
Sécuriser la maintenance
[modifier|modifier le code]Lors d'une modification d'un programme, les tests unitaires signalent les éventuellesrégressions.En effet, certains tests peuvent échouer à la suite d'une modification, il faut donc soit réécrire le test pour le faire correspondre aux nouvelles attentes, soit corriger l'erreur se situant dans le code.
Documenter le code
[modifier|modifier le code]Les tests unitaires peuvent servir de complément àl'API,il est très utile de lire les tests pour comprendre comment s'utilise une méthode. De plus, il est possible que la documentation ne soit plus à jour, mais les tests eux correspondent à la réalité de l'application.
Fonctionnement
[modifier|modifier le code]On définit généralement 4 phases dans l'exécution d'un test unitaire:
- Initialisation(fonction
setUp
): définition d'un environnement de test complètement reproductible (unefixture). - Exercice:le module à tester est exécuté.
- Vérification(utilisation de fonctions
assert
): comparaison des résultats obtenus avec un vecteur de résultat défini. Ces tests définissent le résultat du test: SUCCÈS (SUCCESS
) ou ÉCHEC (FAILURE
). On peut également définir d'autres résultats comme ÉVITÉ (SKIPPED
). - Désactivation(fonction
tearDown
): désinstallation desfixturespour retrouver l'état initial du système, dans le but de ne pas polluer les tests suivants. Tous les tests doivent être indépendants et reproductibles unitairement (quand exécutés seuls).
Utilisation
[modifier|modifier le code]Il s'agit pour le programmeur de tester unmodule,indépendamment du reste du programme, ceci afin de s'assurer qu'il réponde auxspécifications fonctionnelleset qu'il fonctionne correctement en toutes circonstances. Cette vérification est considérée comme essentielle, en particulier dans les applications critiques. Elle s'accompagne couramment d'une vérification de lacouverture de code(évaluation de la couverture structurelle), qui consiste à s'assurer que l'ensemble destestsconduit à exécuter l'ensemble (ou une fraction déterminée) des instructions présentes dans le code.
L'ensemble des tests unitaires doit être rejoué après une modification du code afin de vérifier qu'il n'y a pas derégressions(l'apparition de nouveaux dysfonctionnements). L'emploi d'une « stratégie de test » particulièrepeutlimiter les tests à rejouer, par exemple: une analyse d'impact des modifications, corrélée à une preuve d'indépendance des modules, permet de cibler les cas de test unitaire à rejouer.
Commencer par les tests
[modifier|modifier le code]Un test doit correspondre aux spécifications de l'application, il faut donc écrire les tests en premier puis les faire passer par la suite plutôt que d'écrire le code avant et de prendre le risque d'être influencé par celui-ci lors de la rédaction des tests[12].Bob Martin[13],grand défenseur de la méthodeTDD,propose unmodèlesimple pour l'écriture des tests unitaires:
- Écrire une fonction de test qui doit obtenir un résultat défini dans les spécifications. Ce code appelant un code qui n'existe pas encore, celui-ci doit échouer. Ceci a pour but de définir une fonction qui teste « quelque chose ».
- Écrire le code (le minimum de « quelque chose ») pour faire réussir le test.
- Une fois le test en succès, rajouter un autre test pour obtenir un résultat légèrement différent, en faisant varier les entrées par exemple. Ce nouveau test fera faillir le code principal.
- Modifier le code principal pour faire réussir les tests.
- Recommencer, en éliminant etrefactorisantles éventuelles redondances dans le code des tests. On refactorise en même temps le code principal que le code des tests.
- Un test unitaire doit tester une caractéristique et une seule. On ne définit pas un «scénario» de test complexe dans un test unitaire.
- Il est déconseillé de tester les détails d'implémentation telles que les fonctions privées d'une classe, on se concentrera à tester les fonctions publiques, c'est-à-dire les interfaces avec lesquelles les acteurs extérieurs interagissent. Ainsi, on découple les tests de l'implémentation et on se concentre sur la vérification du comportement attendu tout en gardant une flexibilité sur la manière d'arriver au résultat souhaité.
Utiliser des mocks
[modifier|modifier le code]Lesmockssont des objets permettant de simuler un objet réel de façon contrôlée. Dans certains cas, l'utilisation de mock est primordiale, pour un gain de temps decouverture de code,et de fiabilité des tests[14]
- pour simuler unebase de données,unservice web,etc., les interactions entre l'application et ces outils prennent du temps, l'utilisation de mock pour simuler leurs fonctionnements peut être un gain de temps considérable;
- certains cas d'erreurs sont très difficile à reproduire, l'utilisation de mock permet ici de simuler une erreur pour pouvoir traiter ce cas et donc améliorer la couverture de code, par exemple le catch d'une exception;
- sans l'utilisation de mock, le test peut retourner une erreur ne provenant pas du code qui est testé (par exemple une base de données).
Cependant, une utilisation abusive de mock peut avoir l'effet inverse, notamment allonger le temps d'exécution des tests, rendre les tests compliqués à comprendre et à maintenir.
Génération
[modifier|modifier le code]La plupart desframeworksde la famillexUnitpermettent la génération des classes de test unitaire. Cependant ces frameworks ne fournissent que le squelette des classes. Les tests devront donc être écrits par le développeur.
La génération de tests unitaires est un sujet important pour les chercheurs et plusieurs conférences s'intéressent à cette problématique, telles queInternational Symposium on Software Testing and Analysis(ISSTA),International Conference on Software Engineering(ICSE) etAutomated Software Engineering(ASE).
Correction de test unitaire
[modifier|modifier le code]Lors d'une modification dans le code d'un programme, il se peut que certains tests ne passent plus; dans ce cas, le développeur doit déterminer si cela vient du code en lui-même ou du test: si cela vient du test, le développeur doit modifier son test car la suppression de celui-ci entraînerait une augmentation des chances de régression du programme. Certains chercheurs ont développé des outils pour résoudre ce problème.
ReAssert[15]est un outil suggérant des réparations pour un test qui échoue, il analyse les tests à modifier et suggère des changements au développeur, si cette suggestion convient au développeur, il peut effectuer le changement en cliquant sur un bouton.
Test unitaire paramétrable
[modifier|modifier le code]Les tests unitaires paramétrables sont des tests unitaires qui prennent des paramètres. Ils peuvent ensuite utiliser des outils comme QuickCheck pour générer des paramètres. Ces tests sont supportés parJUnit,TestNGet NUnit.
En s'appuyant sur des cas concrets d'entrée et sortie, la génération d'Oracle et sur la couverture de test pour minimiser les cas, des chercheurs ont réussi à générer des tests unitaires paramétrables[16].Les résultats de cette méthode sont prometteurs.
Environnements de développement
[modifier|modifier le code]Il existe une multitude de cadriciels (framework) permettant de réaliser facilement des tests unitaires. Il en existe dans les principauxlangages de programmation.Par exempleTest::More
[17]pour lePerl.
Frameworks xUnit
[modifier|modifier le code]Le terme générique «xUnit» désigne un outil permettant de réaliser des tests unitaires dans un langage donné (dont l'initiale remplace « x » le plus souvent).
- AUnit[18]pourAda;
- ASUnit[19]pourActionScript;
- Cppunit[20]pourC++;
- CUnit[21]pourC;
- DUnit pourDelphi;
- FLEXunit pourAdobe Flex;
- GoogleTest[22]et Boost Test[23]pourC++;
- HUnit[24]pourHaskell;
- JSUnit[25],QUnit[26],Unit.js[27]et Jest[28]pourJavaScript;
- JUnit[29]etTestNG[30]pourJava;
- NUnit[31]pour.NET;
- MicrosoftUnit Test[32]pour.NET;
- xUnit[33]pour.NET;
- NUnitASP[34]pourASP.NET(support interrompu depuis le);
- OUnit[35]pourOCaml;
- OCunit pourObjective C;
- PBUnit pourPowerBuilder;
- PHPUnit[36],SimpleTest[37]et Atoum[38]pourPHP;
- plunit pourProlog;
- utPLSQL[39]pourPL/SQL;
- Unittest etPyUnitpourPython;
- TapepourJavaScript;
- Test::Unit pourRuby;
- Test::More pourPerl;
- Typemockpour.NET, C++, C#. Avec Typemock vous pouvez travailler sur legacy code aussi.
- SUnit[40]pourSmalltalk;
- RPGUnit[41]pour RPG;
- ScalaTest pour Scala
- SASUnit[42]pourSAS.
Outils commerciaux
[modifier|modifier le code]Divers outils permettent l'automatisation des tests unitaires:
- Le module TBrun de la suite d'outilsLDRA;
- Tessy (distribution:Hitex Development Tools/Allemagne).
- Ponicode, génération de tests unitaires en Javascript[43].
Articles connexes
[modifier|modifier le code]Notes
[modifier|modifier le code]- (en)Benington, Herbert D., «Production of large computer programs»,Proceedings of the Symposium on Advanced Programming Methods for Digital Computers, Washington, D.C., June 28-29, 1956,Office of Naval Research, Department of the Navy,,p.15-28
- H. D.Benington,«Production of large computer programs»,Proceedings of the 9th international conference on Software Engineering,IEEE Computer Society Press, iCSE '87,,p.299–310(ISBN978-0-89791-216-7,DOI10.5555/41765.41799,lire en ligne,consulté le)
- Norman A.Zimmerman,«System integration as a programming function»,Proceedings of the 1969 24th national conference,Association for Computing Machinery, aCM '69,,p.459–467(ISBN978-1-4503-7493-4,DOI10.1145/800195.805951,lire en ligne,consulté le)
- (en)Gouvernement des Etats Unis d'Amérique, Département de la Défence,MIL-STD-483 Military standard: configuration management practices for systems, equipment, munitions, and computer programs,,Section 3.4.7.2. "The contractor shall then code and test software Units, and enter the source and object code, and associated listings of each successfully tested Unit into the Developmental Configuration"
- (en)Michael F.Tighe,«The value of a proper software quality assurance methodology»,ACM SIGMETRICS Performance Evaluation Review,vol.7,nos3-4,,p.165–172(ISSN0163-5999,DOI10.1145/1007775.811118,lire en ligne,consulté le)
- Camp Smalltalk SUnit
- Simple Smalltalk Testing:With Patterns,inSmalltalk Reportoctobre 1994, Kent Beck
- (en)Ward Cunningham, «Testing Framework»,surwiki.c2.
- Xunit, Martin Fowler
- GNU Based Compilation System for Space Embedded Applications, Blondin, J. P. & Martignano, M., DASIA 98 - Data Systems in Aerospace, Proceedings of the conference held 25-28 May, 1998 in Athens, Greece, Edited by B. Kaldeich-Schü.rmann. ESA SP-422. Paris: European Space Agency, 1998., p.137, "1998ESASP.422..137B", page 138 http://adsbit.harvard.edu//full/1998ESASP.422..137B/0000138.000.html
- 10 Reasons to Write Unit Tests
- Unit Testing Best Practices, Roy Osherove.
- Test First, bob Martin.
- Robert Martin,When to Mock.
- (en)Brett Daniel, Danny Dig, Tihomir Gvero, Vilas Jagannath, Johnston Jiaa, Damion Mitchell, Jurand Nogiec, Shin Hwei Tan et Darko Marinov, «ReAssert: a tool for repairing broken unit tests»,ICSE,(lire en ligne).
- (en)Gordon Fraser et Andreas Zeller, «Generating Parameterized Unit Tests»,ISSTA,(lire en ligne).
- Test::More sur CPAN,entre autresmodules de tests.Voir aussi les articles de l'association desmongueurs de PerldansLinux Magazine Francedisponibles surhttp://articles.mongueurs.net/magazines
- AUnit
- AsUnit
- CppUnitet enversion 2
- CUnit
- GoogleTest
- Boost.Test
- HUnit
- JsUnit
- http://qunitjsUnit testing for Javascript made by the jQuery Foundation
- (en)Unit JS:«Unit testing framework for Javascript».
- (en)«Jest · 🃏 Delightful JavaScript Testing», surjestjs.io(consulté le).
- Welcome to The New JUnit.org! | JUnit.org.
- (en)«TestNG Documentation», surtestng.org(consulté le).
- NUnit - Home
- (en-US)erickson-doug,«Writing Unit Tests for the.NET Framework with the Microsoft Unit Test Framework for Managed Code - Visual Studio», surdocs.microsoft(consulté le).
- (en)«Home > xUnit.net», surxunit.github.io(consulté le).
- NUnitAsp - ASP.NET unit testing
- OUnit
- PHPUnit - Trac
- SimpleTest - Unit Testing for PHP
- Atoum
- utPLSQL
- Simple Smalltalk Testing: With Patterns
- http://rpgunit.sourceforge.net/
- (en)«SASUnit», surSourceForge(consulté le).
- (en)«Ponicode - Quick and easy Javascript unit testing», surponicode(consulté le).