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 :

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 :

# 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) :

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 :