• 10 heures
  • Moyenne

Ce cours est visible gratuitement en ligne.

course.header.alt.is_video

course.header.alt.is_certifying

J'ai tout compris !

Mis à jour le 25/04/2022

Découvrez le Test-Driven Development

Connectez-vous ou inscrivez-vous gratuitement pour bénéficier de toutes les fonctionnalités de ce cours !

Nous pourrions tout à fait ajouter une fonctionnalité, puis la tester en exécutant un script avec des arguments divers, et enfin créer une pull-request sur GitHub. Ou bien la tester manuellement !

Mais dans ce chapitre, nous allons faire un peu différemment. Nous allons nous laisser guider par les tests pour créer la fonctionnalité.

Mais les tests font exactement ce que nous leur demandons de faire, non ?

Les tests vérifient que notre code renvoie ce que nous lui demandons. En soi, nous pourrions tout à fait comprendre notre programme uniquement en lisant les tests ! La suite de tests fait alors office de documentation puisque nous y lisons des exemples d'utilisation de notre programme.

Le Test-Driven Development (TDD), ou développement piloté par les tests, est une technique de développement qui préconise d'écrire les tests avant le code source d'un logiciel.

Kent Beck, le créateur de la méthodologie de projet agile Extreme Programming, a développé cette technique dans les années 2000. Elle s'est par la suite largement répandue dans le monde.

La technique repose sur trois phases complémentaires :

  • Red : Écrire un test unitaire puis le lancer. Évidemment, il échoue.

  • Green : Écrire le code source qui permet de faire passer le test.

  • Refactor : Améliorer le code source.

Le TDD est composé de 3 phases : RED, écrire un test qui échoue ; GREEN, écrire du code qui respecte le test ; REFACTOR, faire passer le test.
Le Test Driven Development

Quels sont les avantages du TDD ? Pourquoi s'astreindre à suivre ces règles et ce processus ?

Uncle Bob, dans cette fantastique vidéo (en anglais), nous rappelle les avantages principaux à suivre une démarche TDD :

  • Temps de débogage réduit : Vous passez moins de temps à débugger car votre code est testé en détail.

  • Confiance : Vous gagnez en confiance et en flexibilité.

  • Documentation : Vos tests deviennent votre documentation et il est plus facile pour d'autres développeurs de l'utiliser.

  • Design : Votre code s'améliore car il devient plus modulaire et facile à tester.

Ajoutez une fonctionnalité en TDD : red / green / refactor

Pour illustrer cette théorie, nous allons implémenter la fonction qui permet de faire la division entre deux nombres en suivant la méthode TDD.

Comment les phases du TDD se traduisent en code ? 

Voyons-le tout de suite !

Red : Écrivez le test

Commençons la première phase du TDD et implémentons un test qui vérifie la division entre deux nombres. Nous allons vérifier que, si on appelle la fonctiondivisionavec comme argument 10 et 5 respectivement le numérateur et le dénominateur, la valeur de retour est égale à 2. En effet, ce n’est un secret pour personne, 10 divisé par 5 est égal à 2.

Créez la fonctiondivisiondans un fichier que vous nommerezdivision.py.

def division(numerator, denominator):
pass

Commençons la première phase du TDD et implémentons un test qui vérifie la division entre deux nombres. Appelons la fonctiondivisionavec les arguments 10 et 5, et vérifions que la valeur de retour est égale à 2.

Ajoutez le code suivant à un nouveau fichier de testtest_division.py.

from division import division
def test_should_make_division():
numerator = 10
denominator = 5
expected_value = 2
assert division(numerator, denominator) == expected_value

Lançons le test... Effectivement, il y a une erreur.

L’exécution du test montre bien qu’il ne passe pas. C’est normal le code source n’existe pas.
Première phase du TDD

Sans surprise, la fonctiondivisionn’a pas d’instructionreturnet renvoie la valeurNone: le test ne passe donc pas. Pour une fois, nous sommes contents d’avoir du rouge dans notre test.

Nous devons maintenant passer à la deuxième étape, donc faire en sorte que ce test passe sans tenir compte du reste de l'application, mais uniquement de ce test.

Green : Écrivez le code

En effet, le bloc de code dans la fonctiondivisionn'existe pas ! Nous allons donc maintenant créer le code nécessaire pour effectuer la division entre le numérateur et le dénominateur. Pour le coup, c’est très simple, nous n’avons besoin que d’une seule ligne.

def division(numerator, denominator):
return numerator / denominator

Relançons... Le test est vert ! Parfait !

Le test est vert et valide l’unité du code implémenté.
Deuxième phase du TDD
Refactor : Refactorez le code

Je me suis rendu compte que nous n’avons pas pris en compte le cas de la division par zéro. Nous devons donc ajouter le code nécessaire pour éviter que le code crashe

Nous avons choisi de modifier le comportement de la fonction et de retourner la valeurNonesi le dénominateur est égal à 0.

Ajoutons d’abord le test qui vérifie la gestion de cette erreur :

def test_should_return_none_with_zero_division():
numerator = 10
denominator = 0
expected_value = None
assert division(numerator, denominator) == expected_value

Et maintenant, vous pouvez ajouter le code qui permet de valider l’ensemble des tests.

def division(numerator, denominator):
try:
return numerator / denominator
except ZeroDivisionError:
return None

Lançons les tests à nouveau !

Les deux tests passent et le refactoring est terminé.
Troisième et dernière phase du TDD

Bonne nouvelle ! Tous les tests sont au vert !

Notez que, si vous aviez décidé d’implémenter la fonction différemment, comme ci-dessous par exemple :

def division(numerator, denominator):
if denominator == 0:
return None
return numerator / denominator

... le refactoring n’aurait pas cassé les tests car la logique du code n’a pas changé. Les tests seraient toujours verts ! Et c’est l’objectif du refactoring : une modification du code ne doit pas casser les tests, mais simplement proposer une amélioration de la logique du code.

Nous avons fini la troisième étape du TDD ! Vous pouvez être fier de vous ! Nous avons donc terminé l’ensemble du cycle du TDD 

Nous pouvons passer à l'écriture du test suivant. Nous aurons alors de nouveau du rouge, puis du vert lorsque nous le corrigerons.

Je vous propose de regarder le screencast ci-dessous, qui reprend les étapes du TDD. Le TDD n’aura plus de secret pour vous !

À vous de jouer !

Il est temps de se mettre au travail ! Je vous propose de mettre en place votre première classe pilotée par les tests.

Votre mission :

Créez une classeBankAccountavec les attributs :

  • le nom du titulaire :name;

  • le numéro du compte :  account_number;

  • le solde du compte :  account_balance.

Ajoutez ensuite les méthodes suivantes :

  • account_informations(): retourne les informations du compte dans un dictionnaire;

  • withdraw(value): soustrait un montant au solde du compte (retrait d’argent) ;

  • deposit(value): ajoute un montant au solde du compte (dépôt d’argent). 

Vous pouvez voir les différentes étapes du TDD grâce aux commits de ce repository GitHub.

En résumé

  • Test Driven Development (TDD) est une pratique de développement logiciel qui consiste à d’abord créer le test unitaire avant de développer la fonctionnalité dans le code source.

  • Le TDD est un cycle de développement itératif suivant la méthode red-green-refactor :

    • Red : Écrire un test unitaire.

    • Green : Écrire le code source qui permet de faire passer le test.

    • Refactor : Améliorer le code source.

C’est bon, c’est promis, cette fois c’est vraiment terminé ! Bravo pour l'ensemble de votre travail tout au long du cours. Et je vous dis à tout de suite dans le dernier chapitre, pour revenir sur vos acquis et valider ensuite vos compétences lors d’un dernier quiz. Je sais que vous adorez les quiz ! 

Exemple de certificat de réussite
Exemple de certificat de réussite