Écrire un programme, c’est bien. Écrire un programme juste, c’est mieux. Nous verrons, ici, comment limiter les erreurs en testant des bouts de code que l’on écrit sur des cas particuliers pour lesquels on connait bien le résultat attendu. Il existe plusieurs méthodes, nous en verrons deux, assert et doctest.
Le développement piloté par les tests ou TDD (pour Test Driven Development) est une méthode d’écriture de programme qui met en avant le fait d’écrire d’abord un test pour chaque spécification du programme puis écrire le code qui permettra au programme de passer ce test avec succès. Cette manière de procéder permet en général de penser en premier lieu aux spécifications voulues, ce qui améliore la structure générale du code produit et permet de s’assurer que l’on dispose de toute une batterie de tests sous la main . Plus particulièrement, le TDD a été théorisé sous forme de trois lois.
Les assertions sont un moyen simple de s'assurer, avant de continuer, qu'une condition est respectée. En général, on les utilise dans des blocstry … except. Voyons comment cela fonctionne : nous allons pour l'occasion découvrir un nouveau mot-clé (encore un),assert. Sa syntaxe est la suivante :
assert test
Si le test renvoieTrue, l'exécution se poursuit normalement. Sinon, une exceptionAssertionErrorest levée.
Voyons un exemple :
var = 15
assert var == 15
assert var == 44
Comme vous le voyez, la ligne 2 s'exécute sans problème et ne lève aucune exception. On teste en effet si var == 15. C'est le cas, le test est donc vrai, aucune exception n'est levée. À la ligne suivante, cependant, le test est var == 44. Cette fois, le test est faux et une exception du typeAssertionErrorest levée (regardez dans la console:-).
Dans le programme testant si une année est bissextile, on pourrait vouloir s'assurer que l'utilisateur ne saisit pas une année inférieure ou égale à 0 par exemple. Avec les assertions, c'est très facile à faire :
annee = input("Saisissez une année supérieure à 0 :")
try:
annee = int(annee) # Conversion de l'année
assert annee > 0
except ValueError:
print("Vous n'avez pas saisi un nombre.")
except AssertionError:
print("L'année saisie est inférieure ou égale à 0.")
L’inconvénient majeur de cette méthode (même si cela peut en fait être un avantage) est que l’on doit traiter une assertion après l’autre car le programme s’arrête dès le premier test qui échoue. En cas de réussite, il ne se passe simplement rien.
Le module doctest permet d’inclure les tests dans la docstring descriptive de la fonction écrite définie par """. On présente dans la docstring, en plus des explications d’usage, des exemples d’utilisation de la fonction tels qu’ils pourraient être tapés directement dans la console Python. Le module doctest (via l’appel à doctest.testmod()) reconnaît les bouts de code correspondant à ces exemples et les exécute pour les comparer à la sortie demandée. On peut alors commenter in situ les tests et leurs raison d’être et avoir une sortie détaillée et globale des tests qui ont réussi ou raté.
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)
Les exemples donnés dans une chaîne de documentation peuvent être testés à l’aide d’un module de Python nommé doctest.
Depuis la console, dans lequel la fonction fact ci-dessus est supposée chargée, tapez les deux lignes suivante:
Svous devriez obtenir :
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). Essayez de remplacer 120 par une autre valeur puis testez
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()
Testez dans le cas avec erreur et sans erreur. Nous constatons que lorsque le programme ne comporte pas d'erreur, rien de se passe. Pour vérifier que tout va bien, il suffit d'ajouter:
doctest.testmod(verbose = True)
Même si l’écriture de tests ne garantit en rien qu’un programme est correct, le fait de réfléchir aux cas limites que l’on peut rencontrer et en écrire une vérification explicite permet d’assainir l’environnement de développement. En particulier dans le cadre d’une application réelle où les demandes sont souvent amenées à être plus spécifiques à mesure que le temps avance, avoir une batterie de tests sous la main permet d’étendre le code existant sans avoir (trop) peur que la modification ne casse complètement ce qui existait déjà. Tout du moins, on s’en rend compte rapidement.
tester le code ci-dessous et insérer des tests en utilisant les deux méthodes (insert et doctest) à vous d'imaginer les erreurs possibles:-)
def moyenne():
"""fonction permettant de calculer ma moyenne trimestrielle"""
arret=""
somme=0
cpt=0
while arret!= "stop":
note=int(input ("entrer votre note"))
somme=somme+note
cpt=cpt+1
arret=input("Si vous souhaitez stopper la saisie, ecrivez stop")
moy=somme/cpt
return moy