Fil d'Ariane

Éviter les régressions avec les tests unitaires

Par Jérôme Megel le 09 janvier 2014
Tests unitaires

Les tests unitaires sont liés à l'écriture des fonctions et reposent sur le caractère prédictif de leur fonctionnement. Les fonctions récupèrent des données en entrée, les traitent en leur sein puis renvoient un résultat. Tester une fonction revient donc à vérifier que, pour une liste d'arguments donnés, la fonction renvoie ce qui est prévu. Ces tests sont nommés « unitaires » car ils ne concernent qu'une fonction à la fois, à la différence des tests fonctionnels dits « d'acceptation ».

Un exemple simple

Soit la fonction .div(a,b) devant renvoyer le résultat de la division de « a » par « b ». Malgré sa simplicité, une telle fonction peut devoir être écrite pour certaines applications, par exemple si « a » et « b » sont autres choses que des nombres… Admettons, par commodité, que cela soit le cas. Les tests unitaires liés à cette fonction devront par exemple vérifier que .div(10,5) renvoie bien 2, que .div(-10,-5) renvoie la même chose, etc. Toutes les possibilités ne pouvant être évaluées, seules les plus décisives seront testées. Par exemple, que se passe-t-il en cas de division par zéro ? Typiquement, le test unitaire devra vérifier qu'une « exception » est « levée » ou que le résultat renvoyé est marqué comme impossible à calculer. Une autre manière d'envisager les tests est de donner une série de valeurs aléatoires à la fonction, de calculer par un autre moyen le résultat attendu et de comparer ce dernier à celui renvoyé par la fonction testée. En plus de leur caractère relativement exhaustifs, ces tests permettent de détecter des cas auxquels le développeur n'a pas songé en développant sa fonction ; on reconnaît ici la technique du « fuzzing » proposé par des logiciels spécifiques, très utile pour vérifier jusqu'à quel point un programme peut supporter des valeurs d'entrée fantaisistes.

Tests non prédictifs

Que se passe-t-il si la fonction n'est pas complètement prédictive ? Prenons l'exemple de la génération de nombres aléatoires. Si une méthode .getARandomNumber() renvoie un nombre entre 0 et 1, comment la tester ? La puissance des tests unitaires permet de donner une réponse partielle à ce problème. Plutôt que de prévoir le comportement de la fonction sur une paire de données du type (arguments, résultat), il est possible de faire subir des tests statistiques à une quantité suffisamment grande de données testées. Par exemple, de nombreuses discussions ont concerné la fonction (équivalent à) .getARandomNumber() des noyaux de certains systèmes d'exploitation. Ces discussions portaient sur le caractère réellement aléatoire des nombres générés, cette question ayant une grande importance en cryptographie. La définition du mot « aléatoire » étant possible grâce aux mathématiques - pensons au test du khi-carré par exemple - il a été possible de valider ou non le caractère aléatoire de ces fonctions.

Automatisation des tests unitaires

Les tests unitaires sont les premiers à être passés par le code quand celui-ci est suivi par un serveur d'intégration continue. Si un test échoue, il n'est en effet pas même besoin de faire passer des tests plus complexes comme les tests fonctionnels. Afin de faciliter leur emploi, certains langages de programmation prévoient un cadre à l'écriture de ces tests : c'est par exemple le cas de Python et de son package unittests. Dans ces langages, l'appel des tests peut être d'autant plus automatisé qu'ils sont conçus sous une forme directement compatible avec le reste du programme.

Conclusion

A première vue, les tests unitaires doublent le travail du développeur qui est contraint d'écrire et sa fonction et le test unitaire vérifiant le fonctionnement de cette dernière. L'expérience montre que l'écriture raisonnée de tests unitaires est au contraire un gain de temps et un gage de qualité. Certaines méthodes de travail dites « agiles » préconisent même d'écrire les tests avant la fonction correspondante ! C'est dire l'importance et le succès des tests unitaires auprès des entreprises soucieuses de promouvoir en interne la qualité de leur code. Il reste à ces dernières à adapter l'écriture de leurs tests unitaires à leurs produits. Par exemple, Roxecom, agence web experte en e-commerce et e-marketing, développe uniquement en PHP et utilise par conséquent PhpUnit pour ses développements, principalement sous Magento.


 

Ajouter un commentaire

Vous avez un projet ?contactez-moi
Me contacter par email