This page was exported from Enseignement de l'informatique et du numérique au lycée Boissy d'Anglas [ https://icn-isn-boissy.yj.fr/wp ] Export date:Wed Feb 26 11:33:22 2025 / +0000 GMT ___________________________________________________ Title: Doctest : une façon originale et pratique de tester… --------------------------------------------------- Objectifs utiliser un outil de test : doctestétablir une méthodologie pour les TP Motivation Vous savez documenter les fonctions à l'aide d'une «chaîne de documentation» (ou «docstring»), c'est-à-dire une chaîne de caractères placée immédiatement après l'en-tête de la fonction. Voici un tel exemple de documentation def fact(n): """ paramètre n : (int) un entier valeur renvoyée : (int) la factorielle de n. CU : n >= 0 Exemples : >>> fact(3) 6 >>> fact(5) 120 """ res = 1 for i in range(2, n + 1): res = res * i return res Cette documentation peut être exploitée avec la fonction help : >>> help(fact) Help on function fact in module __main__: fact(n) paramètre n : (int) un entier valeur renvoyée : (int) la factorielle de n. CU : n >= 0 Exemples : >>> fact(3) 6 >>> fact(5) 120 À faire Utilisez Pyzo pour recopier la fonction fact avec sa docstring dans un fichier que vous nommerez exples_doctest.py,et utiliser la fonction help au niveau de l'interpréteur. Réaliser une telle chaîne de documentation permet à l'utilisateur de la fonction de savoir à quoi peut servir la fonction ;comment il peut l'utiliser ;et quelles conditions il doit respecter pour l'utiliser (CU). et au programmeur de la fonction de préciser le nombre et la nature de ses paramètres ;la relation entre la valeur renvoyée et celle du ou des paramètres ;ses idées avec quelques exemples. (Tout cela bien entendu à condition que cette documentation soit rédigée avant la réalisation du programme et non le contraire.) Mais vous allez découvrir que cela permet davantage encore ! Utiliser le module doctest Les exemples donnés dans une chaîne de documentation peuvent être testés à l'aide d'un module de Python nommé doctest. À faire Depuis l'interpréteur (shell), dans lequel la fonction fact ci-dessus est supposée chargée, tapez les deux lignes >>> import doctest pour importer le module, et >>> doctest.testmod() Vous devez obtenir >>> doctest.testmod() TestResults(failed=0, attempted=2) La fonction testmod du module doctest est allée chercher dans les docstring des fonctions du module actuellement chargé, c'est-à-dire exples_doctest, tous les exemples (reconnaissables à la présence des triples chevrons >>>), et a vérifié que la fonction documentée satisfait bien ces exemples. Dans le cas présent, une seule fonction dont la documentation contient deux exemples (attempted=2) a été testée, et il n'y a eu aucun échec (failed=0). Et si un exemple et la fonction ne sont pas d'accord ? À faire Modifiez le deuxième exemple, en mettant 121 à la place de 120 dans le second exemple. Chargez le fichier dans l'interpréteur (touche F5) et retapez les deux lignes >>> import doctest >>> doctest.testmod() Vous devez obtenir >>> doctest.testmod() ********************************************************************** File "/home/eric/AP1/exples_doctest.py", line 24, in __main__.fact Failed example: fact(5) Expected: 121 Got: 120 ********************************************************************** 1 items had failures: 1 of 2 in __main__.fact ***Test Failed*** 1 failures. Qu'est ce que tout cela révèle ? Tout d'abord que les tests ont échoué et qu'il y a eu 1 échec (cf dernière ligne) et que cet échec est dû à la fonction fact (cf avant dernière ligne).Ensuite que le test incriminé est celui concernant fact(5) pour lequel le test a obtenu (Got) 120 en exécutant la fonction fact, alors qu'il attendait (Expected) 121 selon l'exemple donné par la documentation. Lorsqu'il y a de tels échecs, cela invite le programmeur à vérifier son programme, … ou bien les exemples de sa documentation, comme c'est le cas ici. Rendre automatique les tests Il est très facile de rendre automatique les tests et ainsi de ne plus avoir à faire appel explicitement (et manuellement) à la fonction testmod. Il suffit pour cela d'inclure en fin de fichier les trois lignes : if __name__ == '__main__': import doctest doctest.testmod() À faire Ajoutez ces trois lignes à la fin du fichier exple_doctest.py et exécutez-le ! (F5) Faites le dans le cas d'un test erroné, et dans le cas sans erreur. Que remarquez-vous dans le cas sans erreur ? Rendre les doctests bavards même en cas de succès Un paramètre optionnel de la fonction testmod permet d'obtenir plus d'informations sur les tests effectués mêmes en cas de succès. Il suffit pour cela de rajouter le paramètre ̀`verbose=True`` : doctest.testmod(verbose = True) À faire Faites-le ! Et observez ce que vous obtenez avec des exemples erronéssans exemple erroné. Les sorties complexes Tester les exemples des docstring avec le module doctest peut être source de déboires et de pièges. Vous allez découvrir certains d'entre eux et les remèdes qu'on peut y apporter. Avec les listes Supposez que vous vouliez donner un exemple qui produit la liste des factorielles des entiers de 0 à 5. Vous avez donc complété votre documentation en ajoutant """ paramètre n : (int) un entier valeur renvoyée : (int) la factorielle de n. CU : n >= 0 Exemples : >>> fact(3) 6 >>> fact(5) 120 La liste des factorielles des entiers de 0 à 5 >>> [fact(n) for n in range(6)] [1,1,2,6,24,120] """ Avertissement La ligne blanche entre le deuxième exemple et la phrase qui suit est absolument nécessaire. En son absence, la phrase sera comprise comme faisant partie de la sortie produite par le deuxième exemple, et le test échouera donc. Il est clair que ce nouvel exemple est tout à fait correct. Pourtant, si vous procédez au test vous constaterez que sur les trois exemples testés, l'un a abouti à un échec : le troisième. À faire Faites-le ! Quel est le problème ? Cela vient du fait que la fonction testmode effectue une comparaison litérale entre la réponse fournie par la documentation (Expected ) et celle fournie par l'interpréteur (Got). À faire Examinez attentivement ces deux points (Expected et Got) dans la réponse du test que vous venez d'effectuer. Avez-vous compris ? Le problème, ce sont les espaces que l'interpréteur place après chaque virgule dans l'énumération des éléments de la liste. Dans la documentation, ils n'y sont pas. Comment corriger ce point ? C'est simple, il faut mettre des espaces entre les éléments d'une liste. Mais ce n'est pas si simple. On peut facilement mettre plusieurs espaces, comme ci-dessous : """ paramètre n : (int) un entier valeur renvoyée : (int) la factorielle de n. CU : n >= 0 Exemples : >>> fact(3) 6 >>> fact(5) 120 La liste des factorielles des entiers de 0 à 5 >>> [fact(n) for n in range(6)] [1, 1, 2, 6, 24, 120] """ À faire Faites-le ! Testez ! L'excès d'espaces provoque des erreurs. Si on ajoute, sous forme d'un commentaire la directive #doctest : + NORMALIZE WHITESPACE , alors le test réussit, à condition néanmoins d'avoir mis au moins une espace après chaque virgule. """ paramètre n : (int) un entier valeur renvoyée : (int) la factorielle de n. CU : n >= 0 Exemples : >>> fact (3) 6 >>> fact (5) 120 La liste des factorielles des entiers de 0 à 5 >>> [fact (n) for n in range (6)] ... # doctest: +NORMALIZE_WHITESPACE [1, 1, 2, 6, 24, 120] """ À faire Vérifiez-le ! Avertissement les trois petits points sous les trois chevrons sont indispensables. Avec la directice supplémentaire +ELLIPSIS , on peut même se dispenser d'énumérer explicitement tous les éléments de la liste : """ paramètre n : (int) un entier valeur renvoyée : (int) la factorielle de n. CU : n >= 0 Exemples : >>> fact(3) 6 >>> fact(5) 120 La liste des factorielles des entiers de 0 à 5 >>> [fact(n) for n in range(6)] ... # doctest: +NORMALIZE_WHITESPACE, +ELLIPSIS [1, ..., 24, 120] """ À faire Vérifiez-le ! Attention aux ensembles et dictionnaires Contrairement aux listes ou tuples, les ensembles et les dictionnaires ne sont pas des structures de données séquentielles. Il est impossible de prévoir dans quel ordre un interpréteur Python écrira les éléments de ces structures. Par exemple, on peut très bien avoir >>> {'a', 'b'} {'a', 'b'} comme on peut avoir >>> {'a', 'b'} {'b', 'a'} Il est donc difficile d'illustrer une valeur d'un de ces deux types dans un exemple d'une docstring. Il est préférable de tester l'égalité de deux valeurs [1] : >>> {'a', 'b'} == {'b', 'a'} Voici donc un exemple de ce qu'il est envisageable de placer dans une docstring Un dictionnaire de certaines valeurs de fact : >>> set (n for n in range(5)) == {0, 1, 2, 3, 4} True À faire Vérifiez ce point ! Avec des sorties aléatoires Comment tester des fonctions qui produisent des valeurs aléatoires ? Dans l'absolu, il est impossible de placer un exemple dans la docstring donnant le résultat d'un appel à de telles fonctions puisque les valeurs qu'elles renvoient sont imprévisibles. Par exemple si on veut tester qu'une fonction simulant un dé à six faces ne produit que des nombres compris entre 1 et 6, comment faire ? On peut si on le souhaite vérifier que cette fonction ne renvoie que des nombres compris entre 1 et 6. from random import randrange def de(): """ paramètre : aucun valeur renvoyée : (int) un nombre choisi au hasard compris entre 1 et 6. CU : aucune Exemple : >>> 1 <= de() <= 6 True """ return randrange(1,7) À faire Concevez un test qui vérifie 100 fois qu'aucun nombre produit par la fonction de n'est en dehors de l'intervalle [1,6] . Mais un tel test ne prouve pas que jamais la fonction ne produira un nombre en dehors de cet intervalle. Méthodologie Note Pour chacun des fichiers de programmes Python que vous écrirez durant les séances de TP, ainsi que dans la réalisation du projet de fin de semestre, vous devrez documenter toutes les fonctions avec une docstring donnant des exemples pertinents d'utilisation de ces fonctions ajouter les trois lignes de code suivantes en fin de fichier : if __name__ == "__main__": import doctest doctest.testmod() Pour en savoir plus Voir la documentation de Python. Notes merci à l'université de Lilles pour son cours Algorithmes et Programmation 1. [1]À condition qu'on puisse tester l'égalité des éléments de ces structures. --------------------------------------------------- Images: --------------------------------------------------- --------------------------------------------------- Post date: 2019-10-09 12:06:24 Post date GMT: 2019-10-09 10:06:24 Post modified date: 2020-05-18 10:50:55 Post modified date GMT: 2020-05-18 08:50:55 ____________________________________________________________________________________________ Export of Post and Page as text file has been powered by [ Universal Post Manager ] plugin from www.gconverters.com