Tester une fonction

Pourquoi ne pas écrire les tests avant de coder ?

La plupart du temps, si ce n’est pas tout le temps, lors de la conception d’un algorithme, on connait déjà ce que l’on doit obtenir en sortie sur quelques exemples.

Exercice:

a) Quelle est la distance qui sépare les nombres 2 et 5 ? les nombres 7 et -2 ?
b) On souhaite écrire une fonction distance qui renvoie la distance entre deux nombres donnés. Si on disposait déjà de cette fonction, que devrait-on obtenir dans la console Python ?

>>> distance(2, 5)
...                 # à compléter
>>> distance(7, -2)
...                 # à compléter

Réponses

Comment prendre en compte les tests avant de coder ?

On va encore compléter la docstring de la fonction avec les tests cette fois et faire appel à un module doctest.

  1. La première partie ne pose aucun problème.

    def distance(a, b):
        """
        Renvoie la distance séparant les nombres a et b.
        :param a: (float) un nombre
        :param b: (float) un nombre
        :return d: (float) la distance entre a et b
        >>> distance(2, 5)
        3
        >>> distance(7, -2)
        9
        """
        # reste à taper le code de la fonction comme à l'habitude
    
Code complet de la fonction
  1. Ne reste plus désormais qu’à faire intervenir un module qui saura trouver et tester les tests présents dans la docstring.
    En toute fin de programme, il suffit d’ajouter ces quelques lignes:

    import doctest
    doctest.testmod(verbose = True, optionflags = doctest.NORMALIZE_WHITESPACE)
    

    En détails, doctest est sensible à tous les caractères présents y compris les éventuels espaces présents par défaut. Le module teste littéralement ce qui est écrit dans les tests proposés. optionflags = doctest.NORMALIZE_WHITESPACE avertit le module de ne pas prêter attention aux éventuels espaces en plus ou en moins présents.

    verbose = True permet d’afficher tous les détails des tests effectués par le module. Cela peut s’avérer bien utile pour identifier les problèmes rencontrées.

Code au complet

Après exécution du programme, la console Python devrait afficher:

Affichage dans le cas où les tests sont réussis
Affichage dans le cas où un test a échoué

Comment éviter d’afficher les éventuels tests réalisés dans un des modules importés ?

Vous aurez probablement noté que, lors des tests, il est fait référence à __main__ qui désigne l'instance en cours.

Cela signifie qu’il effectue les tests demandés dans ce présent fichier, mais aussi ceux éventuellement présents dans les modules importés.

Pour y remédier, il suffit d’ajouter en toute fin de tous les fichiers importés avant les tests éventuels une condition à vérifier afin de ne prendre uniquement en compte que les tests de l'instance en cours.

Exemple sur le présent fichier:

def distance(a, b):
    """
    Renvoie la distance séparant les nombres a et b.
    :param a: (float) un nombre
    :param b: (float) un nombre
    :return d: (float) la distance entre a et b
    >>> distance(2, 5)
    3
    >>> distance(7, -2)
    9
    """
    if a >= b:
        d = a - b
    else:
        d = b - a
    return d

if __name__ == "__main__":         
    import doctest
    doctest.testmod(verbose = True, optionflags = doctest.NORMALIZE_WHITESPACE)

Si on importe ce présent module pour faire appel à la fonction distance(), les tests présents dans la boucle if ne seront pas effectués en dehors de celui-ci.