Je travaille sur différents projets dans lesquels les personnes utilisent des outils BDD (Business Driven Developement) comme cucumber ou JBehave.
C’est une très bonne idée cela permet, par exemple, d’avoir des spécifications par l’exemple. Néanmoins, ce n’est pas simple d’écrire du BDD !
Dans cet article je vais tenter d’expliquer ce que doit être un bon BDD.
Mauvaises pratiques :
Commençons avec quelques mauvaises pratiques que j’ai trop souvent rencontrées.
Imaginons que nous devons tester un logiciel d’assurance.
Mauvaise pratique #1 : Faire le lien avec l’IHM (Interface Homme Machine)
Utiliser l’IHM pour écrire votre test est une mauvaise option. Malheureusement cette mauvaise pratique peut être encouragée par des composants comme « seleniumcucumber » (si vous l’utilisez sans redéfinir les étapes des tests).
Exemple :
Scenario: insured should be older than 18
Given I navigate to "http://www.insuranceadress.com/insurance"
And I enter "01/01/2001" into input field having id "birthdate"
When I click on element having id "next"
Then I should see a message "Insured should be older than 18"
And I should see page title as "Please enter birth date of insured"
Cet exemple n’est pas à suivre pour plusieurs raisons:
- L’IHM n’est pas assez stable (car elle évolue beaucoup) ce qui engendre beaucoup de maintenance sur un test de ce type.
- Le test est souvent verbeux car vous souhaitez suivre l’IHM
- Le test n’est pas candidat à du « Test first » car l’IHM est obligatoire pour pouvoir l’écrire (comment connaitre autrement les IDs des différents champs ?)
- Le test ne montre pas l’impact business mais plus le comportement de l’IHM. Cela n’aide donc pas à comprendre le vrai comportement de l’application et donc d’avoir une documentation vivante.
Je ne dis pas que vous ne pouvez pas faire du test IHM en BDD, seulement que la fonctionnalité ne devrait pas être liée à la logique de l’IHM.
Mauvaise pratique #2 : trop verbeux
Une autre mauvaise habitude est l’utilisation du business model et de définir tous les attributs de tous les objets à manipuler dans les tests. La raison derrière cela est que les attributs sont obligatoires et doivent être définis.
Voici un autre exemple :
Scenario: Woman should have a 10% discount
Given a person:
| FirstName | June |
| Name | Doe |
| BirthDate | 20/01/1985 |
| BirthPlace| LA |
| Sex | Female |
And a car:
| Brand | VW |
| Name | Beetle |
| Year | 2000 |
| Engine | 1100cc |
| Place | 4 |
| Color | red |
And a insurance type:
| Comprehensive | No |
| Collision | Yes |
| Usage | Pleasure|
| Accident | No |
When insurer wants to compute the insurance prize
Then it should be 315$
Une bonne règle est de définir uniquement les données qui sont importantes pour le test (c’est le même principe que la simplification des tables de décisions). Si les données sont obligatoires mais n’influent pas sur le test il faut laisser la liberté de décider la valeur à utiliser à la personne qui automatise le test. Cela sera alors dans le code de définition des étapes et sera plus facile à maintenir et réutiliser.
De plus, en lisant le cas en exemple, à part avec le titre, vous ne savez pas ce que fait le test ni quelles sont les données importantes.
A la fin, même la personne qui lit le test ne connait plus le but de ce test.
Mauvaise pratique #3 : tester des fonctionnalités triviales
Il arrive que des personnes test des créations triviales ce qui donne des tests triviaux comme celui-ci :
Scenario: Add an insured
When insurer creates a person:
| FirstName | June |
| Name | Doe |
| BirthDate | 20/01/1985 |
| BirthPlace| LA |
| Sex | Female |
Then the list of persons should be:
| FirstName | Name | BirthDate | BirthPlace | Sex |
| June | Doe | 20/01/1985 | LA | Female |
Ce type de test doit être fait avec les tests unitaires. De plus il n’y a pas de règle métier qui s’applique à ce test. Oui, vous devez tester la création quand des règles métiers s’y appliquent (comme les opérations, les cas d’erreurs, les liens vers d’autres objets…), mais tester une création triviale ne vaut vraiment pas le coût (et crée de la redondance)
Mauvaise pratique #4 : Dépendance entre les tests
Une autre mauvaise pratique que j’ai rencontrée avec le BDD est d’avoir des « tests liés » dans lesquels on utilise les données des tests précédents pour les tests d’après. Cela veut dire que le BDD n’est pas indépendant et très compliqué à lire.
Scenario: premium increase when recording an second accident in a year
Given the scenario "record a first accident" was passed
When insured records a new accident on his car
Then premium increase of 10% should be applied on my contract
Le principal problème est de ne pas connaitre les prérequis si vous n’avez pas lu le scenario précédent… et ceux d’avants si le scénario précédent est également lié à un autre scénario antérieur.
Une bonne règle pour les tests (BDD ou non) est d’avoir des tests indépendants. Un test BDD a besoin d’une description claire dans sa partie « Given ».
Il est également très compliqué de faire du retest quand on doit ré-exécuter tous les tests précédents.
Mauvaise pratique #5 : Objectifs multiples
Une bonne pratique bien connue du test est d’avoir uniquement 1 objectif par test. Cela est le cas quel que soit le niveau de tests.
Vous ne devez donc pas écrire des tests BDD avec plusieurs objectifs.
Exemple :
Scenario: premium increase when recording an second accident in a year
Given an insurance contract
When insured records a new accident on his car
Then premium should be the same than before
When insured records a new accident on his car
Then premium increase of 10% should be applied on my contract
Il ne devrait y avoir qu’un seul « then » à la fin (un « And » est également possible), sinon vous retombez dans les travers précédents (ou des objectifs multiples) et il devient compliqué de comprendre quand et pourquoi un test est en échec
Mauvaise pratique #6 : Pas d’exemple
Quelque fois, le BDD n’est plus un exemple mais uniquement une règle. C’est clairement une mauvaise pratique car cela n’aide pas le développeur à comprendre.
Scenario: review accidents
Given a list of accidents
When insurer wants to review the list of accidents
Then only accidents in status "to review" should be displayed
Vos tests doivent être un vrai exemple avec des valeurs (même si vous devez définir une valeur minimale quand dans l’exemple Mauvaise pratique #2, cela doit rester un exemple). Dans ce BDD le test est en succès même avec une liste d’accident vide et tend donc à ne rien montrer.
Bonnes pratiques :
La première chose à faire est d’éviter les mauvaises pratiques. Cela donnera à votre test de bonnes chances d’être fiable et compréhensible.
Utilisez le passé avec « Given », le présent avec « When » et le futur (should) avec Then.
C’est une très bonne habitude d’utiliser cette petite règle. Cela permet de reconnaitre le type d’étape d’un seul coup d’œil et évite les confusions.
Les actions sont clairement différentes selon ce qui est écrit :
- Given a contract was created (setup)
- When a contract is created (trigger)
- Then a contract should be created (assertion)
Utilisez la 3ème personne
Il y a débat entre utiliser 1ère et la 3ème personne. Quel est le meilleur point de vue ? Il n’y a pas de bonne réponse mais j’ai la conviction que les étapes de tests devraient être à la 3ème personne.
Commencez avec un état « vide »
Avant le « Given » d’un scénario, nous devons considérer qu’il n’y a aucune donnée présente. Par contre, « aucune donnée » dépend du système, toutes les données de référence doivent évidemment être présentes.
Si, pour une fonctionnalité spécifique vos tests ont besoin de la même donnée, utilisez simplement le « Backgroud keyword » (dans cucumber). Il vous permet de mettre un contexte à tous vos tests (le « Given » dans le BackGround est exécuté pour tous les tests).
Cela veut également dire que vous devez « nettoyer » vos données persistantes afin d’assurer que chaque test débute dans un état « vide ».
Soyez cours et lisible
Finalement, un grand avantage du BDD est de fournir une documentation vivante. Vous pouvez utiliser vos tests comme une documentation. L’automatisation rend « vivant » vos tests et permet donc d’avoir une documentation à jour.
Mais si vous voulez bénéficier de cet avantage, votre BDD doit être lisible et compréhensible par tout membre du projet. Evitez donc les tests technique (pensez DDD : Data Driven Development) et validez vos fichiers avec le métier est un très bon moyen d’atteindre cet objectif.
Article de Laurent Bouhier, publié initialement sur ce blog et traduit de l’anglais par Marc Hage Chahine
Article très bien détaillé, merci pour toutes ces explications!
J’aimeJ’aime
> Utilisez le passé avec « Given », le présent avec « When » et le futur (should) avec Then.
Pour ma part j’utilise verbe d’état pour le « Given », verbe d’action pour le « When » et état avec should pour le « Then »
Tout au présent,
Cela force au passage à préciser le persona qui fait l’action (administrateur, editeur, visiteur, client, …)
ce qui donne:
– Given a contract is created (setup)
– When the user creates a contract (trigger)
Then a contract should be created (assertion)
les cas dependant de temporality peuvent généralement bien s’adapter
– When the user subscribed 2 month ago
devient
– When the user is subscribed since 2 month
J’aimeJ’aime
> j’ai la conviction que les étapes de tests devraient être à la 3ème personne
Je confirme, pour une raison très claire, le personna a l’origine de chaque état ou action est important
Egalement privilégier « the » plutôt que « a », sinon le scenario laisse entendre que les action ou état peuvent être dépendantes de personnes différente
ex:
– When a user clicks on the « Find » button
– And a user promotes a product
parlons nous du même user?
on utilisant « the » cela devient implicite
on pourra alors être plus précis également quand plusieurs users interviennent
– When the user clicks on the « Find » button
– And the user promotes a product
– Given the first user is a visitor
– And the second user is a sales editor
– When the firt user clicks on the « Find » button
– And the second user promotes a product
J’aimeJ’aime
Alexandre, je suis d’accord avec la plupart de tes remarques et je te remercie…
MAIS je n’aime pas, comme je l’ai dit, les scénarios qui se basent sur l’IHM et ton exemple :
When the user clicks on the « Find » button
Est clairement de ce genre, il suffit de dire que l’utilisateur cherche un produit, là il *doit* y avoir un bouton « Find »…
De plus, quand il y a plusieurs utilisateurs, je trouve pratique de leur donner un petit nom, cela évite de mettre des « first » et « second »… sur chaque action.
En tout cas merci pour le partage
J’aimeJ’aime
Merci pour le partage, totalement en phase avec ce qui est écrit et avec des exemples c’est très clair.
J’y ajouterai quelques éléments que j’ai appris avec un webinar de la société SmartBear / HipTest sur les principes BRIEF, j’ai trouvé ça assez intéressant et ça reprend en grande partie ce qui a été dit :
– Business language : comme dit, ne pas être autocentré sur l’IHM mais sur l’usage
– Real data : des vraies données et non des données de tests
– Intentional revealing : Ce qu’on attend au lieu de steps ultra détaillés
– Essential : les données essentielles au test, ne pas s’embarrasser à saisir les données inutiles au test
– Focused : pas de multi-test au sein d’un test, le test doit rester « atomique » un but précis
Un scenario = 5 lignes maxi, + facile à lire et + facile à comprendre
J’aimeJ’aime