NSI 1ère

Tests unitaires simples
Exercices corrigés

Maîtrisez les tests unitaires simples : unittest, assertions et bonnes pratiques de vérification grâce à ces 5 exercices détaillés.

Concepts & Exercices
\(\text{Test} = \text{Fonction} + \text{Entrée} + \text{Attendu} + \text{Résultat}\)
Structure d'un test
unittest
class Test(unittest.TestCase)
Framework de test
assert
self.assertEqual(a, b)
Comparaison
Test
def test_fonction(self):
Méthode de test
🧪
Test unitaire : Test qui vérifie le bon fonctionnement d'une unité de code (fonction, méthode).
Assertion : Vérification qui échoue si la condition n'est pas remplie.
🔧
Vérification : Processus de validation du comportement attendu du code.
Exercice 1
Écrire un test unitaire simple pour une fonction de calcul
Exercice 2
Tester une fonction avec plusieurs cas d'entrée
Exercice 3
Tester le comportement d'erreur d'une fonction
Exercice 4
Créer des tests pour une classe de calculatrice
Exercice 5
Tester une fonction de manipulation de listes
Corrigé : Exercices 1 à 3
1 Test simple
Définition :

Test unitaire : Test qui vérifie qu'une petite partie du code (généralement une fonction) fonctionne correctement.

Méthode de test :
  1. Importer le module unittest
  2. Créer une classe qui hérite de unittest.TestCase
  3. Écrire une méthode de test commençant par test_
  4. Utiliser une assertion pour comparer le résultat attendu au résultat obtenu
import unittest def addition(a, b): return a + b class TestAddition(unittest.TestCase): def test_addition_positifs(self): resultat = addition(3, 5) self.assertEqual(resultat, 8) def test_addition_negatifs(self): resultat = addition(-2, -3) self.assertEqual(resultat, -5)
Étape 1 : Définir la fonction à tester

Créer la fonction que vous souhaitez tester (ici: addition)

Étape 2 : Créer la classe de test

Hériter de unittest.TestCase pour bénéficier des assertions

Étape 3 : Écrire la méthode de test

Appeler la fonction et vérifier le résultat avec self.assertEqual

Test réussi :

Le test vérifie que addition(3, 5) retourne 8

Règles appliquées :

Nom de méthode : Commencer les méthodes de test par test_

Assertions : Utiliser des assertions pour comparer les résultats

Indépendance : Chaque test doit être indépendant des autres

2 Cas multiples
Définition :

Cas de test : Ensemble d'entrées et de sorties attendues pour valider le comportement d'une fonction dans divers scénarios.

import unittest def est_pair(nombre): return nombre % 2 == 0 class TestEstPair(unittest.TestCase): def test_nombres_pairs(self): self.assertTrue(est_pair(2)) self.assertTrue(est_pair(0)) self.assertTrue(est_pair(-4)) def test_nombres_impairs(self): self.assertFalse(est_pair(1)) self.assertFalse(est_pair(3)) self.assertFalse(est_pair(-5)) def test_grands_nombres(self): self.assertTrue(est_pair(1000)) self.assertFalse(est_pair(999))
Étape 1 : Identifier les cas limites

Tester avec des valeurs positives, négatives, zéro, grands nombres

Étape 2 : Créer des méthodes spécifiques

Organiser les tests par catégorie pour une meilleure lisibilité

Étape 3 : Vérifier tous les cas

S'assurer que la fonction fonctionne correctement dans toutes les situations

. ---------------------------------------------------------------------- Ran 3 tests in 0.001s OK
Tous les tests passent :

La fonction est_pair fonctionne correctement pour tous les cas testés

Règles appliquées :

Cas limites : Tester avec des valeurs extrêmes et frontières

Organisation : Regrouper les tests par catégorie de cas

Complétude : Couvrir autant de cas que possible

3 Gestion des erreurs
Définition :

Test d'erreur : Test qui vérifie qu'une fonction lève une exception dans certaines conditions.

import unittest def diviser(a, b): if b == 0: raise ValueError("Division par zéro impossible") return a / b class TestDiviser(unittest.TestCase): def test_division_normale(self): resultat = diviser(10, 2) self.assertEqual(resultat, 5.0) def test_division_par_zero(self): with self.assertRaises(ValueError): diviser(10, 0) def test_message_exception(self): with self.assertRaises(ValueError) as context: diviser(15, 0) self.assertIn("Division par zéro", str(context.exception))
Étape 1 : Identifier les conditions d'erreur

Déterminer quand la fonction devrait lever une exception

Étape 2 : Utiliser assertRaises

Vérifier que l'exception est bien levée dans les cas appropriés

Étape 3 : Vérifier le message d'erreur

S'assurer que le message d'erreur est significatif

. ---------------------------------------------------------------------- Ran 3 tests in 0.001s OK
Gestion des erreurs :

Le test vérifie que la fonction lève une exception appropriée dans les cas d'erreur

Règles appliquées :

Exceptions : Tester que les exceptions sont levées dans les bons cas

Messages : Vérifier que les messages d'erreur sont clairs

Robustesse : S'assurer que le code gère correctement les erreurs

Corrigé : Exercices 4 à 5
4 Classe de test
Définition :

Test de classe : Test qui vérifie le comportement d'une classe entière avec ses attributs et méthodes.

import unittest class Calculatrice: def __init__(self): self.memoire = 0 def addition(self, a, b=None): if b is None: resultat = self.memoire + a self.memoire = resultat return resultat else: resultat = a + b self.memoire = resultat return resultat def reset(self): self.memoire = 0 class TestCalculatrice(unittest.TestCase): def setUp(self): self.calc = Calculatrice() def test_addition_simple(self): resultat = self.calc.addition(5, 3) self.assertEqual(resultat, 8) def test_addition_avec_memoire(self): self.calc.addition(5, 3) # memoire = 8 resultat = self.calc.addition(2) # 8 + 2 = 10 self.assertEqual(resultat, 10) def test_reset_memoire(self): self.calc.addition(10, 5) # memoire = 15 self.calc.reset() self.assertEqual(self.calc.memoire, 0)
Étape 1 : Utiliser setUp pour l'initialisation

Créer les objets nécessaires avant chaque test

Étape 2 : Tester les méthodes individuellement

Vérifier chaque méthode de la classe avec des cas pertinents

Étape 3 : Tester les interactions entre méthodes

Vérifier que les méthodes interagissent correctement entre elles

. ---------------------------------------------------------------------- Ran 3 tests in 0.001s OK
Test de classe complet :

Les tests vérifient le comportement de la classe et de ses méthodes

Règles appliquées :

setUp : Utiliser setUp pour initialiser les objets avant chaque test

Indépendance : Chaque test doit pouvoir s'exécuter seul

Complétude : Tester toutes les méthodes et leurs interactions

5 Manipulation de listes
Définition :

Test de structures de données : Test qui vérifie les opérations sur des structures de données comme les listes.

import unittest def filtrer_positifs(nombres): """Retourne une liste contenant uniquement les nombres positifs""" return [n for n in nombres if n > 0] def inverser_liste(liste): """Retourne la liste inversée""" return liste[::-1] class TestManipulationListes(unittest.TestCase): def test_filtrer_positifs(self): resultat = filtrer_positifs([1, -2, 3, -4, 0, 5]) self.assertEqual(resultat, [1, 3, 5]) def test_filtrer_tous_negatifs(self): resultat = filtrer_positifs([-1, -2, -3]) self.assertEqual(resultat, []) def test_inverser_liste(self): resultat = inverser_liste([1, 2, 3, 4]) self.assertEqual(resultat, [4, 3, 2, 1]) def test_inverser_vide(self): resultat = inverser_liste([]) self.assertEqual(resultat, []) def test_inverser_un_element(self): resultat = inverser_liste([42]) self.assertEqual(resultat, [42])
Étape 1 : Tester le comportement nominal

Vérifier que la fonction fonctionne correctement dans des cas normaux

Étape 2 : Tester les cas limites

Vérifier le comportement avec des listes vides, un seul élément, etc.

Étape 3 : Tester les cas spéciaux

Vérifier avec des valeurs particulières (négatives, zéro, etc.)

..... ---------------------------------------------------------------------- Ran 5 tests in 0.001s OK
Tests de listes complets :

Les tests couvrent les cas normaux, limites et spéciaux pour les fonctions de manipulation de listes

Règles appliquées :

Cas limites : Tester avec des listes vides, un seul élément

Spécificités : Considérer les particularités des données manipulées

Complétude : Couvrir tous les scénarios d'utilisation possibles

Cours bien détaillé
\(\text{Qualité} = \frac{\text{Tests réussis}}{\text{Total des tests}} \times 100\%\)
Couverture des tests
🎯
Définition : Un test unitaire est un test automatisé qui vérifie le comportement d'une unité de code spécifique.
📏
Objectif : Vérifier que chaque composant du programme fonctionne correctement de manière isolée.
📐
Structure : Entrée → Fonction → Résultat → Assertion (comparaison avec la valeur attendue).
📝
Avantages : Détection rapide des bugs, documentation du code, refactorisation en toute sécurité.
💡
Conseil : Écrire les tests avant le code (TDD) pour clarifier les exigences
🔍
Attention : Ne pas ignorer les tests qui échouent - ils révèlent des bugs
Astuce : Utiliser des noms descriptifs pour les méthodes de test
📋
Méthode : Suivre le modèle AAA (Arrange-Act-Assert)
Vérification : Exécuter régulièrement les tests pour garantir la qualité
Types d'assertions :
  • assertEqual(a, b) : Vérifie que a == b
  • assertTrue(x) : Vérifie que x est vrai
  • assertFalse(x) : Vérifie que x est faux
  • assertIn(item, liste) : Vérifie que item est dans liste
  • assertRaises(exception) : Vérifie qu'une exception est levée
Règles importantes :
  • Chaque test doit être indépendant des autres
  • Les tests doivent être rapides à exécuter
  • Les noms des tests doivent décrire clairement ce qui est testé
  • Les tests doivent couvrir à la fois les cas normaux et les cas limites
  • Les tests doivent être maintenus à jour avec le code
Tests unitaires simples Débogage et vérification