CHAPITRE 7

Débogage et tests

Introduction

Par Mark Hammond, co-auteur de Python Programming on Win32 (O’Reilly)

Mon premier ordinateur personnel était un Z80 avec 64 kilo-octets de mémoire, qui fonctionnait avec CP/M. Avoir cette machine chez moi m’a permis de l’explorer en profondeur. Turbo Pascal venait juste d’apparaître et semblait représenter une évolution naturelle par rapport aux différents dialectes de BASIC et aux assembleurs que j’avais utilisés jusqu’alors. Déjà à cette époque, je voulais développer des bibliothèques réutilisables pour mes programmes et, à mesure que mes compétences et mon expérience professionnelle évoluaient, j’ai continué à m’intéresser à la construction d’outils pour les développeurs ainsi qu’à l’écriture d’applications pour les utilisateurs non experts.

Les outils d’aide aux développeurs sous-entendent souvent débogage et tests. Lorsque l’on évoque ces deux opérations, on pense souvent à des débogueurs interactifs mais les concepts du débogage et des tests sont bien plus larges. Ils constituent parfois un cycle inséparable : les tests permettent parfois de découvrir des bogues et l’on débogue jusqu’à avoir compris la cause d’une erreur afin de la corriger. Ce processus est répété autant de fois que nécessaire.

Souvent, le débogage et les tests sont plus insidieux. Je suis un fervent admirateur de l’instruction assert de Python et je l’utilise toujours pour déboguer et tester mes programmes. Les gros projets utilisent souvent des stratégies pour intégrer directement ces opérations dans l’application elle-même, via des journaux centralisés et des traitements d’erreurs, par exemple. Cela dit, on pourrait objecter que ce type de débogage et de tests convient mieux aux gros projets qu’aux activités post-mortem que je viens de décrire.

Python, notamment, propose plusieurs techniques pour faciliter la tâche des développeurs. Grâce à la nature introspective et dynamique du langage (qui est le résultat de la philosophie de Guido, et qui part du principe que les développeurs sont des adultes consentants), les techniques de débogage ne sont limitées que par votre imagination. Vous pouvez remplacer des fonctions en cours d’exécution, ajouter des méthodes aux classes et extraire à peu près n’importe quoi de votre programme pendant qu’il s’exécute : tout cela est très simple avec Python.

Dans ce chapitre, vous découvrirez un sujet à la mode : les tests unitaires jouent, aujourd’hui, un rôle assez différent des tests traditionnels qui s’intéressent surtout à la recherche des bogues une fois le programme écrit. Désormais, dès les premières phases de développement, de plus en plus de programmeurs se reposent sur les tests unitaires pour les guider. Cette façon de procéder évite la survenue des bogues et joue un rôle déterminant dans le refactoring, l’optimisation et le portage. La version actuelle de la bibliothèque standard de Python fournit deux modules consacrés aux tests unitaires, unittest et doctest ; avec Python 2.4, ces deux modules sont reliés, comme vous le verrez dans l’une des recettes de ce chapitre. Si vous ne connaissez pas encore le concept moderne des tests unitaires, ces recettes vous ouvriront l’appétit : pour le satisfaire, ce chapitre donne également quelques références à des ouvrages récents traitant de ce problème.

Outre celles consacrées aux tests, vous trouverez également ici un bel ensemble de recettes dont même le critique le plus acharné devrait se régaler. Que vous vouliez personnaliser les journaux d’erreur, approfondir les informations que Python fournit dans les traces ou toute autre chose, vous avez frappé à la bonne porte. Mettez votre serviette, le festin va commencer !

7.1 Empêcher l’exécution de certaines instructions conditionnelles et de certaines boucles

Par Chris McDonough, Srinivas B et Dinu Gherman

Problème

Vous voulez empêcher temporairement l’exécution de certaines instructions conditionnelles ou itératives pendant que vous développez ou déboguez un programme.

Solution

L’approche la plus simple consiste à modifier votre code pour ajouter 0: # juste après le mot-clé if ou while. Comme 0 est considéré comme faux, cette section de code ne s’exécutera pas. Modifiez, par exemple :

 if i < 1:
  traitement()
 while j < k:
  j = truc(j, k)

pour obtenir ce code :

 if 0: # i < 1:
  traitement()
 while 0: # j < k:
  j = truc(j, k)

Si vous devez bloquer/débloquer simultanément de nombreuses sections de code au cours du développement ou du débogage, vous pouvez également définir une variable booléenne (un flag), ok = False, par exemple :

 if ok and i < 1:
 traitement()
 while ok and j < k:
 j = truc(j, k)

Pour autoriser temporairement l’exécution des différentes sections, il suffit alors de modifier la valeur du flag (ok = True). Vous pouvez même utiliser plusieurs flags. N’oubliez pas de supprimer les parties ok and lorsque le développement et le débogage sont terminés, car ils ne feraient que...