C7.3 : Tests
Généralités
L'utilisation de tests, en particulier pour les fonctions, est une étape importante. Elle permet de limiter les risques de bugs lors de l'écriture et lors de la mise à jour du code.
Il est en général souhaitable d'écrire une série de tests dès que les spécifications de la fonction sont établies, avant de coder.
Le choix des tests est important :
- - les cas particuliers donnés dans la spécification de la fonction doivent être testés ;
- - les cas limites des préconditions de la fonction doivent être testés ;
- - les tests doivent êtres variés et prendre en compte l'ensemble des situations correspondant aux préconditions de la fonction.
Par exemple :
- - si le paramètre d'une fonction est un entier, on pensera à tester un entier négatif, un entier positif, ainsi que 0 et éventuellement -1 et 1 ;
- - si le paramètre d'une fonction est une liste, on pensera à tester la liste vide...
Les tests avec le module testmod
Rappels sur la syntaxe avec un exemple
La fonction mathématique factorielle(n) donne le produit des nombres de 1 à n. De plus factoriel(0) = 1.
Voici un programme avec :
- - une fonction dont on a précisé la docstring (spécifications et doctests) et qui permet de calculer la factorielle d'un nombre ;
- - un programme principal avec le lancement automatique de la validation des tests.
# Définition des fonctions
def fact(n):
"""
Calcul et renvoie factoriel de n.
Paramètre n : (int) un entier positif
Valeur renvoyée : (int) la factorielle de n.
Exemples :
>>> fact(3)
6
>>> fact(5)
120
"""
pass
# Programme principal
if __name__ == '__main__':
import doctest
doctest.testmod(verbose = True)
A faire (sur feuille puis sur ordinateur) :
- 1) Le choix des tests proposés vous semble-t-il judicieux ? Compléter les tests.
- 2) Écrire le code de la fonction.
- 3) Tester la fonction pour savoir si elle passe les tests.
Applications
Application 1 (sur feuille)
On souhaite écrire une fonction qui prend une liste de nombres entiers en paramètres et renvoie la somme des nombres de cette liste.
1) Proposer une série de tests pour cette fonction.
2) Écrire le code de la fonction (y compris sa docstring avec les tests) et le programme principal pour valider les tests.
Application 2 (sur feuille puis sur ordinateur)
La fonction suivante est censée tester si la valeur v est présente dans la liste t.
def est_dans(v, t):
i = 0
while i < len(t) - 1 and t[i] != v:
i = i + 1
return i < len(t)
1) Rédiger des tests pour cette fonction afin de montrer qu'elle est incorrecte.
2) Corriger la fonction.
Les tests avec les assertions
Présentation
Il est parfois nécessaire de procéder à des tests sans modifier une fonction (par exemple, si la fonction est dans un module à part ou si c'est une fonction récursive...). Dans ce cas, l'utilisation du module testmod n'est pas possible directement (remarque : elle pourrait se faire en englobant la fonction dans une autre fonction).
Une autre façon de faire des tests est d'utiliser les assertions.
Exemples de syntaxes
def fact(n):
"""
Calcule et renvoie factoriel de n.
Paramètre n : (int) un entier strictement positif
Valeur renvoyée : (int) la factorielle de n
"""
pass
# Programme principal
if __name__ == '__main__':
assert fact(0) == 1
assert fact(1) == 1
assert fact(4) == 4
print("Tous les tests sont ok")
Applications
Application 1 (sur feuille)
On considère la fonction suivante :
def t(b):
a = 0
for i in range(len(b)):
a += b[i]
return a
1) Améliorer la lisibilité du code de cette fonction.
2) Écrire un programme principal avec une série de tests sous forme d'assertions.
Application 2 (sur feuille puis sur ordinateur)
On considère le programme ci-dessous :
def somme(n):
'''
@param n : (int) un entier positif ou nul.
'''
s = 0
for i in range(0,n+1):
s = s + i
return s
# === Partie principale ===
def est_correcte():
from random import randint
liste = [randint(0,100) for _ in range(21)]
for n in liste:
assert somme(n) == n*(n+1)/2
return True
if est_correcte():
print("La fonction donne bien le résultat attendu !")
1) Que fait la fonction somme ? Compléter la docstring de cette fonction.
2) Que fait la "partie principale" du programme ? Ajouter des commentaires au code.
3) Modifier le programme pour que la valeur limite 0 soit systématiquement testée.
TD : Une fonction qui teste une fonction de tri d'une liste
On considère une fonction tri(liste) qui prend une liste d'entiers en paramètre et trie par ordre croissant les éléments de cette liste (le code de cette fonction n'est pas utile pour la suite).
On souhaite écrire une fonction qui automatise le test de la fonction tri().
1) Écrire la fonction est_triee(liste) qui renvoie True si la liste passée en paramètre est triée dans l'ordre croissant ou False dans le cas contraire.
2*) Écrire une fonction ont_meme_contenu(liste1, liste2) qui renvoie True si les deux listes passées en paramètres ont exactement les mêmes éléments (pas forcément dans le même ordre) ou False dans le cas contraire. On n'utilisera pas de fonction de tri pour cela.
3) Ecrire le code la la fonction test_fonc_tri() qui teste la fonction tri. Cette fonction doit :
- - générer une liste aléatoire de 10 entiers ;
- - faire une copie de cette liste (cela se fait avec le code
l2 = l1[:]) oul2 = list(l1); - - appliquer la fonction
trià la liste copiée ; - - vérifier, à l'aide d'une assertion, que la liste triée l'est effectivement ;
- - vérifier, à l'aide d'une assertion, que la liste triée contient les mêmes éléments que la liste initiale.