Loading AI tools
De Wikipédia, l'encyclopédie libre
En programmation informatique, le test 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'un logiciel ou d'une portion d'un programme (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éthodes Extreme programming (XP) ou Test Driven Development (TDD) ont remis les tests unitaires, appelés « tests du programmeur », au centre de l'activité de programmation.
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 projet SAGE au symposium sur les méthodes de programmation avancée organisé par la marine 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 du programme 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 des tests 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 1994 Kent Beck décrit un environnement cadre de test pour le langage Smalltalk, qui deviendra SUnit[6] par la suite[7],[8]. En 1997, Kent Beck rencontre Erich Gamma avec lequel il crée JUnit qui, par sa popularité, entraînera la création de nombreux frameworks de tests unitaires, cet ensemble se nomme xUnit[9].
À la même époque, ATTOL Unit test est développé, puis utilisé par Sextant Avionique en 1998[10]
On écrit un test pour confronter une réalisation à sa spécification. Le test dé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. Le test permet de vérifier que la relation d'entrée / sortie donnée par la spécification est bel et bien réalisée.
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.
Lors d'une modification d'un programme, les tests unitaires signalent les éventuelles ré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.
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.
On définit généralement 4 phases dans l'exécution d'un test unitaire :
setUp
) : définition d'un environnement de test complètement reproductible (une fixture).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
).tearDown
) : désinstallation des fixtures pour 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).Il s'agit pour le programmeur de tester un module, indépendamment du reste du programme, ceci afin de s'assurer qu'il réponde aux spécifications fonctionnelles et 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 la couverture de code (évaluation de la couverture structurelle), qui consiste à s'assurer que l'ensemble des tests conduit à 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 de régressions (l'apparition de nouveaux dysfonctionnements). L'emploi d'une « stratégie de test » particulière peut limiter 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.
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éthode TDD, propose un modèle simple pour l'écriture des tests unitaires :
Les mocks sont 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 de couverture de code, et de fiabilité des tests[14]
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.
La plupart des frameworks de la famille xUnit permettent 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 que International Symposium on Software Testing and Analysis (ISSTA), International Conference on Software Engineering (ICSE) et Automated Software Engineering (ASE).
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.
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 par JUnit, TestNG et 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.
Il existe une multitude de cadriciels (framework) permettant de réaliser facilement des tests unitaires. Il en existe dans les principaux langages de programmation. Par exemple Test::More
[17] pour le Perl.
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).
Divers outils permettent l'automatisation des tests unitaires :
Seamless Wikipedia browsing. On steroids.
Every time you click a link to Wikipedia, Wiktionary or Wikiquote in your browser's search results, it will show the modern Wikiwand interface.
Wikiwand extension is a five stars, simple, with minimum permission required to keep your browsing private, safe and transparent.