TP sur les tests et les bugs

Objectifs et prérequis

Prérequis : cours sur la mise au point des programmes

À l’issue de ce TP, vous saurez :

  • utiliser les exceptions pour rendre un programme robuste face aux saisies incorrectes ;
  • identifier et corriger des bogues dans un programme existant ;
  • écrire des tests unitaires avec assert et avec pytest ;
  • mesurer et comparer les performances d’un programme à l’aide de time.perf_counter().

Introduction

Les activités pratiques qui suivent ont pour objectif de vous faire appliquer les notions présentées dans le cours :

  • les exceptions ;
  • les bogues ;
  • les tests unitaires ;
  • les performances.

PizzaError

Une pizzeria souhaiterait créer une sorte de drive automatique pour ses clients afin qu’ils puissent commander en ligne une pizza selon les stocks disponibles.

Un stagiaire a déjà commencé l’écriture d’un programme prototype : pizza_drive.py .

Cependant comme vous allez pouvoir le constater, le programme est largement perfectible :

  • mauvaise gestion des saisies (caractères VS entier) ;
  • commande de pizza malgré les stocks vides ;
  • plantage lorsque l’on commande la pizza 3.

À l’aide des exceptions, rendez ce programme plus robuste et plus ergonomique pour le client, c’est à dire sans plantage inopiné.

Chasse aux bogues

  1. Téléchargez et décompressez l’archive bogues.zip .
  2. Pour chacun des scripts :
    • trouvez l’origine du bogue ;
    • proposez un correctif pour le rendre fonctionnel.

Tests unitaires

À votre tour de mettre en œuvre les tests unitaires sur une classe Rectangle à réaliser. Vous utiliserez la méthode simple avec le mot clef assert, puis la librairie pytest dans un second temps.

Classe Rectangle

L’entreprise GEOFORME développe des logiciels et outils de dessin industriel.

Le développeur avant vous dans le service a commencé à développer une classe Rectangle disponible dans le fichier rectangle.py . Il a principalement défini l’API de la classe et positionné des TODO comme ci-dessous dans chaque méthode :

# TODO : compléter le code de la méthode
pass

Si vous détectez des problèmes potentiels, vous pourrez les signaler en levant une Exception comme ci-dessous :

# Un problème potentiel...
if probleme == True:
    raise Exception("Un problème est survenu")

Le responsable du service vous demande de finir de coder cette classe et d’écrire les tests unitaires qui permettront de la valider et de l’intégrer dans le reste du logiciel de dessin industriel.

Concernant les tests unitaires, vous créerez deux versions et donc deux fichiers :

  • tests_rectangle_assert.py : version avec le mot-clef assert
  • tests_rectangle_pytest.py : version avec la librairie pytest

Optimisation et performances

Chasse aux performances

Johnny Begood participe en ce moment à un challenge algorithmique sur une plate-forme en ligne. Pour le problème n°10, il doit écrire un programme qui affiche le \(2000\text{-ième}\) nombre premier. Il a écrit un code qui fonctionne parfaitement bien (le résultat est \(17~389\)), mais la plate-forme a fixé une limite de temps d’exécution (< 100 ms) pour valider le challenge et son programme est trop lent.

Chronométrage

  1. Téléchargez son code source : probleme_v00.py .
  2. À l’aide de la fonction perf_counter() du module time, mesurez et affichez le temps d’exécution de son programme et plus particulièrement de sa fonction rechercher_nieme_nombre_premier().
  3. Notez le résultat moyen obtenu sur trois exécutions et confirmez le refus par la plate-forme.

Première optimisation idiomatique

Harry a entendu parlé qu’en Python les boucles for étaient plus performantes que les boucles while.

  1. Créer un nouveau script programme_v02.py, copiez/collez le code de la version v00 et modifiez le code de sa fonction etre_premier() pour remplacer la boucle while par une boucle for.
  2. Chronométrez le temps d’exécution obtenu et notez le résultat moyen sur trois lancement. Comparez le temps entre les versions v00 et v02. Est-ce suffisant ?

Seconde optimisation algorithmique

Après avoir lu la page wikipédia consacrée au nombres premiers, il découvre que le plus grand facteur possible pour un nombre non premier N est \(\sqrt{N}\).

  1. Créez un nouveau script programme_v03.py à partir de la précédente version et modifiez la limite de la boucle for de \(n-1\) à \(\sqrt{n}\).
  2. Chronométrez cette nouvelle version comme précédemment et conclure.

Profilage

Effectuez un profilage du script de départ probleme_v00.py et notez les résultats :

  • pour la fonction rechercher_nieme_nombre_premier() :
    • nombre d’appels ;
    • temps moyen d’exécution ;
    • temps total d’exécution.
  • pour la fonction etre_premier() :
    • nombre d’appels ;
    • temps moyen d’exécution ;
    • temps total d’exécution.