fiche mémo1 min de lecture
programme
En une phrase
Un contrat s'écrit trois fois : en français dans la docstring, en assert dans un jeu de tests écrit avant le code, en assert dans la méthode pour refuser un appel interdit.
À mémoriser
- Docstring : le contrat écrit dans le code ;
help(Pile.depiler)l'affiche sans ouvrir le corps. - Précondition : ce que l'appel doit garantir avant ; postcondition : ce que la méthode promet après.
- Une promesse du contrat, un
assert: c'est ainsi que s'écrit un jeu de tests. - Le jeu de tests ne dépend que du contrat, donc il s'écrit avant le code.
- Un bon jeu de tests échoue tant que le code n'existe pas et passe une fois qu'il est juste : il définit « fini ».
- Le succès d'un jeu de tests ne garantit pas la correction d'un programme, seulement celle des cas écrits.
- Le test vit dehors et accuse l'implémentation ; l'assertion vit dedans et accuse l'appelant.
À savoir reconnaître
| Situation | Ce que c'est |
|---|---|
assert p.depiler() == "R" après empiler(7), empiler("R") | un test : dehors, accuse l'implémentation |
assert not self.est_vide() en première ligne de depiler | une précondition : dedans, accuse l'appelant |
assert len(p) == 2 juste après p.sommet() | test d'une absence d'effet : sommet ne retire rien |
| Le test échoue sur une classe sans corps | normal : il liste ce qu'il reste à écrire |
| Une implémentation fausse passe le test | un cas manque au jeu de tests |
IndexError: pop from empty list | message qui parle des entrailles, pas du contrat : précondition non écrite |
Pièges courants
- Tester l'implémentation (
p.elements == [...]) au lieu du contrat. - N'empiler qu'un élément pour tester LIFO : une file passerait aussi.
- Conclure qu'un code est juste parce que ses tests passent.
assert (condition, "message"): un tuple non vide est toujours vrai, l'assertion ne saute jamais.- Ne rien écrire sur
depiler()ousommet()d'une pile vide : le code décide alors à la place du contrat. - Compter sur
assertpour la sécurité :python -Oles désactive toutes. - Le jeu de tests se relance à chaque modification, pas une seule fois.
Syntaxe Python
class Pile:
def depiler(self):
"""Retirer l'élément du sommet et le renvoyer.
Précondition : la pile n'est pas vide."""
assert not self.est_vide(), "depiler exige une pile non vide"
return self.elements.pop()
def tester_pile(fabriquer_une_pile):
p = fabriquer_une_pile()
assert p.est_vide()
p.empiler(7)
p.empiler("R")
assert p.sommet() == "R"
assert len(p) == 2 # sommet ne retire rien
assert p.depiler() == "R"
assert p.depiler() == 7
assert p.est_vide()