Numérique et Sciences Informatiques1ère

Tests et validation
Exercices corrigés

Maîtrisez les tests et la validation : test unitaire, validation des entrées, tests fonctionnels, couverture de code, débogage grâce à ces 5 exercices détaillés.

Concepts & Exercices
Test \land Validation = Qualité
Principe fondamental
Test Unitaires
tester_fonction(f(x))
Validation d'une fonction individuelle
Validation Entrées
valider(type, plage)
Vérification des données reçues
Couverture de Code
instructions_executées / total_instructions
Pourcentage de code testé
🎯
Définition : Les tests permettent de vérifier le bon fonctionnement d'un programme.
🔍
Validation : Processus qui garantit que les données sont conformes aux attentes.
🛡️
Sécurité : La validation empêche les injections malveillantes.
📊
Qualité : Les tests assurent la fiabilité du logiciel.
Exercice 1
Écrire une fonction de test pour une fonction qui calcule la moyenne
Exercice 2
Valider une adresse e-mail selon un format spécifique
Exercice 3
Tester une fonction de conversion Celsius → Fahrenheit
Exercice 4
Identifier et corriger une fonction avec des erreurs de validation
Exercice 5
Calculer la couverture de code d'une suite de tests
Corrigé : Exercices 1 à 3
1 Test unitaire
Définition :

Test unitaire : Vérifie qu'une petite partie de code (unité) fonctionne correctement.

Méthode de test :
  1. Identifier la fonction à tester
  2. Préparer des cas de test (valeurs d'entrée et résultats attendus)
  3. Appeler la fonction avec les cas de test
  4. Comparer les résultats avec les valeurs attendues
  5. Signaler les différences
def moyenne(liste): if not liste: return None return sum(liste) / len(liste) def test_moyenne(): assert moyenne([10, 20, 30]) == 20.0 assert moyenne([5]) == 5.0 assert moyenne([]) is None print("Tous les tests passent !")
Étape 1 : Analyser la fonction à tester

La fonction moyenne prend une liste de nombres et retourne leur moyenne arithmétique.

Étape 2 : Préparer les cas de test

Nous testons trois scénarios : une liste normale, une liste avec un seul élément, une liste vide.

Étape 3 : Écrire les assertions

Chaque assertion vérifie que la fonction retourne la valeur attendue pour une entrée donnée.

Moyenne([10, 20, 30]) = 20.0
Réponse finale :

La fonction de test vérifie que la fonction moyenne fonctionne correctement pour différents cas.

Règles appliquées :

Test unitaire : Tester chaque fonction indépendamment

Cas limites : Tester les cas extrêmes comme les listes vides

Assertions : Vérifier que les résultats correspondent aux attentes

2 Validation des entrées
Définition :

Validation : Processus qui vérifie que les données sont conformes aux exigences.

import re def valider_email(email): pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$' return re.match(pattern, email) is not None def test_validation_email(): emails_valides = ["test@example.com", "user.name@domain.fr"] emails_invalides = ["invalid", "@domain.com", "user@.com"] for email in emails_valides: assert valider_email(email) == True for email in emails_invalides: assert valider_email(email) == False print("Tous les tests de validation passent !")
Étape 1 : Définir le format attendu

Un email valide suit le format : nom@domaine.extension

Étape 2 : Créer l'expression régulière

L'expression régulière vérifie que l'email respecte le format standard.

Étape 3 : Tester avec des cas valides et invalides

Nous testons à la fois des emails valides et invalides pour s'assurer que la validation fonctionne.

Email valide: test@example.com → True
Réponse finale :

La fonction valide les emails selon un format prédéfini en utilisant des expressions régulières.

Règles appliquées :

Expressions régulières : Outil puissant pour valider des formats complexes

Validation : Protège contre les injections et les erreurs

Test bidirectionnel : Vérifier à la fois les cas valides et invalides

3 Conversion de température
Définition :

Conversion : Transformation d'une valeur d'un système à un autre selon une formule précise.

def celsius_to_fahrenheit(celsius): return celsius * 9/5 + 32 def test_conversion(): # Cas de base assert celsius_to_fahrenheit(0) == 32 assert celsius_to_fahrenheit(100) == 212 # Cas décimaux assert abs(celsius_to_fahrenheit(37) - 98.6) < 0.1 # Cas négatifs assert celsius_to_fahrenheit(-40) == -40 print("Tous les tests de conversion passent !")
Étape 1 : Identifier la formule de conversion

La formule est : F = C × 9/5 + 32

Étape 2 : Tester des cas connus

Nous utilisons des points de référence connus : 0°C = 32°F, 100°C = 212°F

Étape 3 : Gérer les valeurs spéciales

-40°C est égal à -40°F, ce qui constitue un test intéressant.

0°C → 32°F
Réponse finale :

La fonction convertit correctement les températures avec des tests pour valider la précision.

Règles appliquées :

Précision numérique : Utiliser des tolérances pour les comparaisons flottantes

Cas spéciaux : Tester des valeurs extrêmes ou particulières

Formule exacte : S'assurer que la conversion suit la formule mathématique correcte

Corrigé : Exercices 4 à 5
4 Détection d'erreurs
Définition :

Débogage : Processus d'identification et de correction des erreurs dans le code.

# Fonction avec erreurs def diviser(a, b): resultat = a / b return resultat # Correction def diviser_corrigee(a, b): if b == 0: raise ValueError("Division par zéro impossible") if not isinstance(a, (int, float)) or not isinstance(b, (int, float)): raise TypeError("Les paramètres doivent être des nombres") resultat = a / b return resultat def test_diviser(): try: diviser_corrigee(10, 0) assert False, "Erreur attendue" except ValueError: pass assert diviser_corrigee(10, 2) == 5.0 print("Tous les tests de division passent !")
Étape 1 : Identifier les erreurs possibles

La division par zéro provoque une erreur, ainsi que des types incorrects.

Étape 2 : Ajouter des validations

Nous ajoutons des vérifications pour éviter les erreurs courantes.

Étape 3 : Tester les cas d'erreur

Nous vérifions que les exceptions sont levées correctement.

diviser_corrigee(10, 2) = 5.0
Réponse finale :

La fonction corrigée gère les erreurs potentielles et fournit des messages clairs.

Règles appliquées :

Gestion des erreurs : Vérifier les cas limites et lever des exceptions appropriées

Validation des types : S'assurer que les paramètres sont du bon type

Test des erreurs : Vérifier que les exceptions sont correctement levées

5 Couverture de code
Définition :

Couverture de code : Mesure du pourcentage de code exécuté par les tests.

def fonction_a_tester(x, y): if x > 0: if y > 0: return x + y else: return x - y else: return 0 def calculer_couverture(): # Lignes exécutées : 3, 4, 5, 7, 8 # Total lignes de code : 8 # Couverture = 5/8 = 62.5% pass def test_complet(): # Test branche positive assert fonction_a_tester(5, 3) == 8 # Test branche négative assert fonction_a_tester(5, -3) == 8 # Test branche zéro assert fonction_a_tester(-5, 3) == 0 print("Tous les chemins sont couverts !")
Étape 1 : Analyser les branches de code

La fonction a plusieurs chemins d'exécution conditionnelle (if/else).

Étape 2 : Créer des tests pour chaque branche

Nous créons des cas de test qui exécutent chaque chemin possible.

Étape 3 : Calculer la couverture

Nombre de lignes exécutées / nombre total de lignes de code.

Couverture = 100% (toutes les branches testées)
Réponse finale :

Les tests couvrent toutes les branches de la fonction, assurant une bonne couverture de code.

Règles appliquées :

Couverture des branches : Tester chaque chemin possible dans le code

Couverture de ligne : S'assurer que chaque ligne est exécutée au moins une fois

Qualité du code : Une haute couverture de code indique une meilleure qualité

Cours bien détaillé
\text{Qualité} = \frac{\text{Tests réussis}}{\text{Tests totaux}} \times 100
Indicateur de qualité
🎯
Définition : Les tests vérifient le bon fonctionnement d'un programme.
🛡️
Validation : Vérifie que les données sont conformes aux attentes.
🔍
Débogage : Processus d'identification et de correction des erreurs.
📊
Couverture : Pourcentage de code exécuté par les tests.
💡
Conseil : Commencer par tester les cas simples avant les cas complexes
🔍
Attention : Ne pas oublier de tester les cas limites (entrées extrêmes)
Astuce : Utiliser des frameworks de test comme unittest pour automatiser
📋
Méthode : Écrire les tests avant le code (TDD - Test Driven Development)
Vérification : Vérifier que chaque fonction est testée indépendamment
Types de tests :
  • Test unitaire : Teste une seule fonction ou méthode
  • Test d'intégration : Teste l'interaction entre plusieurs modules
  • Test fonctionnel : Vérifie que le programme répond aux besoins fonctionnels
  • Test de performance : Vérifie les performances du programme
Techniques de validation :
  • Validation de type : Vérifie que les variables sont du bon type
  • Validation de plage : Vérifie que les valeurs sont dans les bornes acceptables
  • Validation de format : Utilise des expressions régulières pour valider le format
  • Validation de logique : Vérifie que les règles métier sont respectées
Règles importantes :
  • Chaque fonction devrait avoir ses propres tests unitaires
  • Les tests doivent être indépendants les uns des autres
  • La validation des entrées est essentielle pour la sécurité
  • La couverture de code ne garantit pas l'absence de bugs
  • Les tests doivent être maintenus à jour avec le code
Tests et validation Projet guidé en programmation