Choisir entre test TDD et test BDD

Qu’est ce que le TDD et le BDD ? Quelle technique adopter pour les tests ?

20 Novembre 2020

Le test du logiciel est une discipline qui vise à s'assurer que le logiciel répond à ses objectifs prédéfinis. La planification de cette phase de test commence tôt dans le cycle de vie du développement et elle est d'une importance capitale.

L'activité de test utilise différents types et techniques de tests pour vérifier que le logiciel est conforme à son cahier des charges ou à ses spécifications (vérification du produit) et aux attentes du client (validation du produit), dans cet article nous allons découvrir ensemble les deux techniques de tests les plus utilisées par les équipes IT : TDD et BDD.


Test logiciel

Qu'est -ce que le développement piloté par les tests (TDD) ?

Le développement piloté par les tests (TDD) est un processus de développement logiciel qui repose sur la répétition d'un cycle de développement court : les exigences se transforment en cas de test très spécifiques. Le code est écrit pour que le test réussisse. Enfin, le code est remanié et amélioré pour garantir la qualité du code et éliminer toute dette technique. Ce cycle est bien connu sous le nom de cycle Red-Green-Refactor.


Cycle Red Green Refactor

Dans le cycle Red-Green-Refactor. Nous commençons par un test qui échoue (rouge) et implémentons aussi peu de code que nécessaire pour le faire passer en (vert). Ce processus est également connu sous le nom de Test-First Development. TDD ajoute également une étape Refactor, qui est tout aussi importante pour le succès global.


Test Driven Development

Le diagramme ci-dessus fait un excellent travail en donnant un aperçu facile à digérer du processus. Cependant, la beauté réside dans les détails. Avant d'approfondir chaque étape individuelle, nous devons également discuter de deux approches de haut niveau du TDD, à savoir le TDD ascendant et descendant.

TDD ascendant

L'idée derrière le TDD ascendant, également connu sous le nom de TDD Inside-Out, est de créer des fonctionnalités de manière itérative, en se concentrant sur une entité à la fois, en solidifiant son comportement avant de passer à d'autres entités et à d'autres couches.

Nous commençons par écrire des tests de niveau Unité, procédons à leur implémentation, puis passons à l'écriture de tests de niveau supérieur qui agrègent les fonctionnalités des tests de niveau inférieur, créent une implémentation dudit test agrégé, et ainsi de suite. En construisant, couche par couche, nous arriverons finalement à une étape où le test global est un test de niveau d'acceptation, qui, espérons-le, correspond à la fonctionnalité demandée. Ce processus en fait une approche hautement centrée sur le développeur, principalement destinée à faciliter la vie du développeur.

Avantages Inconvénients
L'accent est mis sur une entité fonctionnelle à la fois Retarde l'étape d'intégration
Les entités fonctionnelles sont faciles à identifier L'ampleur du comportement qu'une entité doit exposer n'est pas claire
Une vision de haut niveau n'est pas nécessaire pour démarrer Risque élevé d'entités n'interagissant pas correctement les unes avec les autres
Aide à la parallélisation La logique métier peut être étendue à plusieurs entités, ce qui la rend peu claire et difficile à tester

TDD descendant

Le TDD descendant est également connu sous le nom de TDD Outside-In ou Développement piloté par les tests d'acceptation (ATDD). Il adopte l'approche inverse. Dans lequel nous commençons à construire un système, en ajoutant de manière itérative plus de détails à la mise en œuvre. Et le décomposer de manière itérative en entités plus petites à mesure que les opportunités de refactoring deviennent évidentes.

Nous commençons par écrire un test de niveau d'acceptation, procédons avec une implémentation minimale. Ce test doit également être effectué de manière incrémentielle. Ainsi, avant de créer une nouvelle entité ou méthode, elle doit être précédée d'un test au niveau approprié. Nous affinons donc itérativement la solution jusqu'à ce qu'elle résout le problème qui a lancé tout l'exercice, c'est-à-dire le test d'acceptation.

Avantages Inconvénients
L'accent est mis sur un scénario demandé par l'utilisateur à la fois Critique pour obtenir le bon test d'assertion, nécessitant ainsi une discussion collaborative entre l'entreprise / l'utilisateur / le client et l'équipe
L'accent est mis sur l'intégration plutôt que sur les détails de mise en œuvre Démarrage plus lent car le flux est identifié par plusieurs itérations
La quantité de comportement qu'une entité doit exposer est claire Possibilités de parallélisation plus limitées jusqu'à ce qu'un système squelette commence à émerger
Les exigences de l'utilisateur, la conception du système et les détails de mise en œuvre sont tous clairement reflétés dans la suite de tests

Cette configuration fait du TDD descendant une approche plus centrée sur l'entreprise / le client. Cette approche est plus difficile à faire car elle repose largement sur une bonne communication entre le client et l'équipe. Cela nécessite également une bonne citoyenneté de la part du développeur, car la prochaine étape itérative doit être soigneusement étudiée. Ce processus s'accélérera avec le temps mais a une courbe d'apprentissage. Cependant, les avantages l'emportent de loin sur les inconvénients. Cette approche se traduit par une collaboration entre le client et l'équipe qui occupe le devant de la scène, un système avec un comportement très bien défini, des flux clairement définis, l'accent est mis sur l'intégration en premier et un résultat très prévisible.

Le cycle de vie Red-Green-Refactor

Forts de la vision de haut niveau évoquée ci-dessus sur la façon dont nous pouvons aborder le TDD, nous sommes libres d'approfondir les trois étapes fondamentales du flux rouge-vert-refactor.

Rouge

Nous commençons par écrire un seul test, l'exécutons (le faisant échouer ainsi) et seulement ensuite passons à l'implémentation de ce test. Ecrire le bon test est ici crucial, tout comme s'entendre sur la couche de test que nous essayons d'atteindre. S'agira-t-il d'un test de niveau d'acceptation ou d'un test de niveau unitaire ? Ce choix est la principale délimitation entre TDD ascendant et descendant.

Vert

Lors de la phase verte, nous devons créer une implémentation pour que le test défini dans la phase rouge passe. L'implémentation doit être l'implémentation la plus minimale possible, faisant passer le test et rien de plus. Exécutez le test et regardez-le réussir.

Créer l'implémentation la plus minimale possible est souvent le défi ici car un développeur peut être enclin, par la force de son habitude, à embellir l'implémentation dès le départ. Ce résultat n'est pas souhaitable car il créera un bagage technique qui, au fil du temps, rendra le refactoring plus coûteux et faussera potentiellement le système en fonction du coût de refactoring. En gardant chaque étape de mise en œuvre aussi petite que possible, nous soulignons davantage la nature itérative du processus que nous essayons de mettre en œuvre. C'est cette fonctionnalité qui nous donnera de l'agilité.

Un autre aspect clé est que le stade rouge, c'est-à-dire les tests, est ce qui anime le stade vert. Il ne devrait y avoir aucune implémentation qui ne soit pilotée par un test très spécifique. Si nous suivons une approche ascendante, cela vient à peu près naturellement. Cependant, si nous adoptons une approche descendante, nous devons être un peu plus consciencieux et nous assurer de créer d'autres tests au fur et à mesure que l'implémentation prend forme, passant ainsi des tests de niveau d'acceptation aux tests de niveau unité.

Refactoriser

L'étape Refactor est le troisième pilier du TDD. Ici, l'objectif est de revoir et d'améliorer la mise en œuvre. L'implémentation est optimisée, la qualité du code est améliorée et la redondance éliminée.

Le refactoring peut avoir une connotation négative pour beaucoup, étant perçu comme un coût pur, corrigeant quelque chose de mal fait la première fois. Cette perception trouve son origine dans des flux de travail plus traditionnels où le refactoring est principalement effectué uniquement lorsque cela est nécessaire, généralement lorsque la quantité de bagages techniques atteint des niveaux intenables, ce qui entraîne un effort de refactoring long et coûteux.

Ici, cependant, la refactorisation fait partie intégrante du flux de travail et est effectuée de manière itérative. Cette flexibilité réduit considérablement le coût du refactoring. Le code n'est pas entièrement retravaillé. Au lieu de cela, il évolue lentement. De plus, le code refactoré est, par définition, couvert par un test. Un test qui a déjà réussi dans une itération précédente du code. Ainsi, la refactorisation peut être effectuée en toute confiance, ce qui se traduit par une accélération supplémentaire. De plus, cette approche itérative d'amélioration de la base de code permet une conception émergente, ce qui réduit considérablement le risque de sur-ingénierie du problème.

Il est d'une importance cruciale que le comportement ne change pas et nous n'ajoutons pas de fonctionnalités supplémentaires pendant la phase de refactorisation. Ce processus permet de refactoriser avec une confiance et une agilité extrême car le code concerné est, par définition, déjà couvert par un test.

Processus de TDD

Comme vous l’aurez compris, la méthodologie TDD suit donc un processus simple en 6 étapes :

1) Rédiger un scénario de test : en fonction des exigences, rédigez un scénario de test automatisé.
2) Exécutez tous les cas de test : exécutez ces cas de test automatisés sur le code actuellement développé.
3) Développez le code pour ces cas de test : si le cas de test échoue, écrivez le code pour que ce cas de test fonctionne comme prévu.
4) Relancez les cas de test : réexécutez les cas de test et vérifiez si tous les cas de test développés jusqu'à présent sont implémentés.
5) Refactoriser votre code : Il s'agit d'une étape facultative. Cependant, il est important de refactoriser votre code pour le rendre plus lisible et réutilisable.
6) Répétez les étapes 1 à 5 pour les nouveaux cas de test : Répétez le cycle pour les autres cas de test jusqu'à ce que tous les cas de test soient implémentés.

Exemple d'implémentation d'un cas de test dans TDD

Supposons que nous ayons l'obligation de développer une fonctionnalité de connexion pour une application qui a comme champs, le nom d'utilisateur, le mot de passe et un bouton d'envoi.

Étape 1 : Créez un scénario de test.



Étape 2 : Exécutez ce scénario de test et nous obtiendrons une erreur indiquant que la page de connexion n'est pas définie et qu'il n'y a pas de méthodes avec des noms enterUserName, enterPassword .

Étape 3 : Développez le code pour ce cas de test. Écrivons le code sous-jacent qui entrera le nom d'utilisateur et le mot de passe et obtiendra un objet de page d'accueil lorsqu'ils sont corrects.



Étape 4 : Exécutez à nouveau le cas de test et nous obtiendrons une instance de la page d'accueil.

Étape 5 : Refactorisons le code pour donner les bons messages d'erreur lorsque les conditions if de la méthode de soumission ne sont pas vraies.



Étape 6 : Écrivons maintenant un nouveau scénario de test avec un nom d'utilisateur et un mot de passe vides.



Maintenant, si vous essayez d'exécuter ce scénario de test, il échouera. Répétez les étapes 1 à 5 pour ce scénario de test, puis ajoutez la fonctionnalité permettant de gérer les chaînes de nom d'utilisateur et de mot de passe vides.

Qu'est-ce que le développement axé sur le comportement (BDD)

Le développement axé sur le comportement (BDD) est un processus de développement logiciel qui encourage la collaboration entre toutes les parties impliquées dans la livraison d'un projet. Il encourage la définition et la formalisation du comportement d'un système dans un langage commun compris par toutes les parties et utilise cette définition comme base d'un processus basé sur le TDD.


Behavior Driven Development

En effet, les expériences vécues avec TDD et ATDD l'ont conduit à proposer le concept BDD, dont l'idée et la revendication étaient de rassembler les meilleurs aspects de TDD et ATDD tout en éliminant les pains points qu'il a identifiés dans les deux autres approches. Ce qu'il a identifié, c'est qu'il était utile d'avoir des noms de test descriptifs et que le comportement de test était beaucoup plus précieux que le test fonctionnel.

Dan North fait un excellent travail en décrivant le BDD comme «Utilisation d'exemples à plusieurs niveaux pour créer une compréhension partagée et une certitude de surface afin de fournir des logiciels qui comptent.»

Quelques points clés ici :

  • Ce qui nous importe, c'est le comportement du système
  • Il est beaucoup plus utile de tester le comportement que de tester les détails d'implémentation fonctionnelle spécifiques
  • Utilisez un langage / une notation commune pour développer une compréhension partagée du comportement attendu et existant entre les experts du domaine, les développeurs, les testeurs, les parties prenantes, etc.
  • Nous atteignons la certitude de surface lorsque tout le monde peut comprendre le comportement du système, ce qui a déjà été mis en œuvre et ce qui est mis en œuvre et que le système est garanti pour satisfaire les comportements décrits

BDD met encore plus l'accent sur la collaboration fructueuse entre le client et l'équipe. Il devient encore plus critique de définir correctement le comportement du système, résultant ainsi en des tests comportementaux corrects. Un piège courant ici est de faire des hypothèses sur la façon dont le système va mettre en œuvre un comportement. Cette erreur se produit dans un test qui est entaché de détails d'implémentation, ce qui en fait un test fonctionnel et non un vrai test comportemental. Cette erreur est quelque chose que nous voulons éviter.

La valeur d'un test comportemental est qu'il teste le système. Il ne se soucie pas de la façon dont il obtient les résultats. Cette configuration signifie qu'un test comportemental ne doit pas changer avec le temps. Sauf si le comportement lui-même doit changer dans le cadre d'une demande de fonctionnalité. Le rapport coût-bénéfice par rapport aux tests fonctionnels est plus important car ces tests sont souvent si étroitement associés à la mise en œuvre qu'un refactor du code implique également un refactor du test.

Cependant, l'avantage le plus substantiel est le maintien de la certitude de surface. Dans un test fonctionnel, un code-refactor peut également nécessiter un test-refactor, ce qui entraîne inévitablement une perte de confiance. Si le test échoue, nous ne savons pas quelle en est la cause : le code, le test ou les deux. Même si le test réussit, nous ne pouvons pas être sûrs que le comportement précédent a été conservé. Tout ce que nous savons, c'est que le test correspond à l'implémentation. Ce résultat est de faible valeur car, finalement, ce qui intéresse le client, c'est le comportement du système. C'est donc le comportement du système que nous devons tester et garantir.

En comparant directement TDD et BDD, les principaux changements sont les suivants :

  • La décision de ce qu'il faut tester est simplifiée ; nous devons tester le comportement
  • Nous exploitons un langage commun qui court-circuite une autre couche de communication et rationalise l'effort ; les user stories telles que définies par les parties prenantes sont les cas de test

Un écosystème de cadres et d'outils a émergé pour permettre une collaboration basée sur un langage commun entre les équipes. Ainsi que l'intégration et l'exécution de comportements tels que des tests en tirant parti des outils standard de l'industrie. Des exemples de cela incluent Cucumber, JBehave et Fitnesse, pour n'en nommer que quelques-uns.


TDD versus BDD

Processus de BDD

Le processus impliqué dans la méthodologie BDD comprend également 6 étapes et est très similaire à celui du TDD.

1) Ecrire le comportement de l'application : Le comportement d'une application est écrit en anglais simple comme un langage par le product owner ou les business analysts ou QAs.
2) Ecrire les scripts automatisés : Ce simple langage anglais est ensuite converti en tests de programmation.
3) Implémenter le code fonctionnel : Le code fonctionnel sous-jacent au comportement est ensuite implémenté.
4) Vérifiez si le comportement réussit : exécutez le comportement et voyez s'il réussit. En cas de succès, passez au comportement suivant, sinon corrigez les erreurs dans le code fonctionnel pour obtenir le comportement de l'application.
5) Refactoriser ou organiser le code : Refactoriser ou organiser votre code pour le rendre plus lisible et réutilisable.
6) Répétez les étapes 1 à 5 pour le nouveau comportement : répétez les étapes pour implémenter plus de comportements dans votre application.

Exemple d'implémentation de comportement dans BDD

Gardons le même exemple utilisé pour la partie TDD. Supposons que nous ayons l'obligation de développer une fonctionnalité de connexion pour une application qui a comme champs le nom d'utilisateur le mot de passe et un bouton d'envoi.

Étape 1 : écrivez le comportement de l'application pour saisir le nom d'utilisateur et le mot de passe.



Étape 2 : écrivez le script de test automatisé pour ce comportement comme indiqué ci-dessous.



Étape 3 : implémentez le code fonctionnel (ceci est similaire au code fonctionnel de l'étape 3 de l'exemple TDD).



Étape 4 : Exécutez ce comportement et voyez s'il réussit. S'il réussit, passez à l'étape 5, sinon déboguez l'implémentation fonctionnelle et réexécutez-la.

Étape 5 : Refactoriser l'implémentation est une étape facultative et dans ce cas, nous pouvons refactoriser le code dans la méthode de soumission pour imprimer les messages d'erreur comme indiqué à l'étape 5 pour l'exemple TDD.




Étape 6 : Écrivez un comportement différent et suivez les étapes 1 à 5 pour ce nouveau comportement.

Différences clés entre TDD et BDD

TDD BDD
Concentrer sur Livraison d'une fonctionnalité Respecter le comportement attendu du système
Approche De bas en haut ou de haut en bas (développement basé sur les tests d'acceptation) De haut en bas
Point de départ Un cas de test Une user story / scénario
Les participants Équipe technique Tous les membres de l'équipe, y compris le client
Langue Langage de programmation Langage humain
Processus Lean, itératif Lean, itératif
Délivre Un système fonctionnel qui répond à nos critères de test Un système qui se comporte comme prévu et une suite de tests qui décrit le comportement du système en langage commun humain
Évite Sur-ingénierie, faible couverture des tests et tests de faible valeur Écart par rapport au comportement prévu du système
Fragilité Un changement de mise en œuvre peut entraîner des modifications de la suite de tests La suite de tests ne doit changer que si le comportement du système doit changer
Difficulté de mise en œuvre Relativement simple pour l’ascendant, plus difficile pour le descendant La plus grande courbe d'apprentissage pour toutes les parties impliquées

Adopter TDD ou BDD ?

En fin de compte, la question ne devrait pas être de savoir s'il faut adopter le TDD ou le BDD, mais quelle approche est la meilleure pour la tâche à accomplir. Très souvent, la réponse à cette question sera les deux. Au fur et à mesure que de plus en plus de personnes participent à des projets plus importants, il deviendra évident que les deux approches sont nécessaires à différents niveaux et à différents moments tout au long du cycle de vie du projet. TDD donnera structure et confiance à l'équipe technique. Alors que BDD facilitera et mettra l'accent sur la communication entre toutes les parties concernées et fournira en fin de compte un produit qui répond aux attentes du client et offre la certitude de surface nécessaire pour garantir la confiance dans l'évolution future du produit.

Comme c'est souvent le cas, il n'y a pas de solution miracle ici. Nous avons plutôt deux approches très valables. La connaissance des deux permettra aux équipes de déterminer la meilleure méthode en fonction des besoins du projet. Une expérience supplémentaire et une fluidité d'exécution permettront à l'équipe d'utiliser tous les outils de sa boîte à outils au fur et à mesure que le besoin se fait sentir tout au long du cycle de vie du projet, obtenant ainsi le meilleur résultat commercial possible.




Consulter nos Formations

Consultez nos Formations sur les Méthodes Agiles, User Stories, Azure DevOps

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *