Un groupe présente cette fonction et ses tests
Exercice de TD · niveau 2 · NSI (première), chapitre 11 — Conduire un projet · Tester pour de vrai
Énoncé
Un groupe présente cette fonction et ses tests. Les tests passent.
def moyenne(notes):
return sum(notes) / len(notes)
def test_moyenne():
assert moyenne([10, 12, 14]) == 12
assert moyenne([8, 8, 8]) == 8
assert moyenne([0, 10, 20]) == 10
- Combien de cas différents ces trois assertions couvrent-elles réellement ?
- Trouver deux appels qui font échouer la fonction.
- Récrire la fonction et compléter le jeu de tests.
Corrigé
1. Un seul. Les trois assertions sont la même : trois notes entières, dont la moyenne tombe juste. Changer les nombres ne change pas le cas — on a écrit trois fois le même test.
C'est le défaut le plus fréquent des jeux de tests d'élèves, et le plus difficile à voir : le compteur affiche « 3 tests », et l'on croit avoir couvert trois situations.
2. Deux appels qui échouent :
moyenne([]) # ZeroDivisionError: division by zero
moyenne(["12", "15"]) # TypeError: unsupported operand type(s)
Le premier est le cas limite qu'aucune des trois assertions n'approchait : une liste vide arrive tôt ou tard, par exemple pour un élève sans note. Le second est le cas d'erreur : des notes lues dans un fichier arrivent sous forme de chaînes de caractères.
3. Il faut d'abord décider ce que la fonction fait d'une liste vide. Deux réponses défendables : renvoyer None, ou refuser l'appel. La seconde est préférable ici — une moyenne de rien n'existe pas, et un None qui circule provoquera une erreur plus loin, à un endroit où l'on ne comprendra plus pourquoi.
def moyenne(notes):
"""Moyenne d'une liste non vide de nombres.
Precondition : len(notes) > 0."""
assert len(notes) > 0, "moyenne d'une liste vide"
return sum(notes) / len(notes)
def test_nominaux():
assert moyenne([10, 12, 14]) == 12
assert moyenne([0, 10, 20]) == 10
def test_limites():
assert moyenne([7]) == 7 # une seule note
assert moyenne([1, 2]) == 1.5 # moyenne non entiere
vide = False
try:
moyenne([])
except AssertionError:
vide = True
# Le verdict est HORS du try : un assert place dedans serait avale
# par le except, et le test passerait quoi qu'il arrive.
assert vide, "aurait du refuser la liste vide"
for test in (test_nominaux, test_limites):
test()
print("ok", test.__name__)
Contrôle : le nouveau jeu couvre quatre cas réellement distincts — plusieurs notes, une seule note, moyenne non entière, liste vide — là où l'ancien en couvrait un, avec le même nombre d'assertions.
La question à se poser devant tout jeu de tests : non pas « combien y a-t-il d'assertions ? », mais « si j'en supprimais une, laquelle me manquerait ? ». Dans le jeu de départ, on pouvait en supprimer deux sans rien perdre.
Les autres exercices de ce chapitre Le cours du chapitre
Un blocage sur cet exercice ? Le tuteur d'Adloun guide par questions, sans donner la réponse.