Dans un précédent article, j’évoquais le but des tests. Je soulignais qu’on ne doit pas tester la conformité d’un code avec une implémentation, mais avec un besoin. Je proposais une nouvelle unité de mesure, le need coverage, pour indiquer l’adéquation du code avec le besoin client. Mais un problème sous-jacent apparait assez vite avec cette réflexion : la personne qui porte la vision du produit, et donc qui est la plus consciente de ce besoin client, c’est le Product Owner. Comment lui permettre de vérifier la conformité de nos tests avec ce besoin ? C’est là qu’entre en jeu le Behaviour Driven Developpement, ou BDD.
Sommaire
Les critères d’acceptation
Souvent lorsqu’une User Story est rédigée, elle contient des critères d’acceptation. Ces critères permettent de définir formellement le comportement attendu d’une fonctionnalité. On les retrouve souvent sous une forme assez codifiée : « Étant donné que … Lorsque … Alors … ». Par exemple, « Étant donné que je ne suis pas connecté Lorsque je clique sur le bouton Mon compte Alors je suis redirigé vers la page de connexion ».
Bien entendu, une user story contient bien plus que les critères d’acceptation, mais ceux-ci réunissent deux éléments importants. D’une part, ils sont une description directe du besoin utilisateur : c’est donc une excellente piste pour notre need coverage. Ensuite, ils sont structurés et codifiés de manière assez répétitive pour permettre de les automatiser.
En complément, il est important de noter que si la rédaction des User Stories est généralement effectuée par le PO, il n’est en rien le seul à pouvoir rédiger ces critères. Le produit est de la responsabilité de toute l’équipe. Le fait que le produit corresponde au besoin est donc aussi de la responsabilité de toute l’équipe… et donc ces critères également.

De story à test : le BDD
À ce point de notre travail, nous avons un ensemble normalement complet décrivant le besoin utilisateur d’une manière structurée. Il est temps de le mettre à profit : c’est là que le BDD entre en jeu.
Il existe plusieurs outils permettant de le mettre en place (Behave ou Cucumber par exemple) mais tous tournent autour de la même idée. Le principe de base est dérivé du TDD : on commence par écrire les tests, puis on écrit le code pour faire marcher les tests. La seule différence, c’est qu’ici, on ne va pas écrire du code pour faire nos tests. À la place, on va réutiliser nos critères d’acceptation.
Pour que nos tests soient efficaces, on va partir du principe qu’il existe un certain nombre de phrases prédéfinies. Ces phrases sont écrites en coopération entre tous les membres de l’équipe et peuvent comprendre des paramètres variables. On va utiliser ces phrases pour écrire nos critères d’acceptation (en les complétant si nécessaire). On va ensuite faire correspondre à chaque phrase un élément de code… et laisser la magie opérer.

Un exemple de BDD ?
Plutôt que de faire de longues explications, je préfère vous proposer un exemple. Imaginons une user story de ce type.
On notera des mots-clefs, Given, When et Then. Ces mots-clefs correspondent bien entendu aux éléments de nos critères d’acceptation. Nous allons ensuite définir nos phrases. J’utiliserais dans cet exemple des syntaxes inspirées par behave en python, mais l’idée générale est la même dans tous les cas.
L’implémentation des tests n’est pas foncièrement différente de ce qu’on aurait pu trouver avec des tests classiques. Mais dans ce cas de figure, nos tests sont basés non pas sur du code, mais sur un élément commun à toute l’équipe, dev team comme PO : les critères d’acceptation. Ils relient directement le code au besoin utilisateur.
Avantage annexe, les phrases sont faites pour être réutilisées. Ainsi, lorsqu’on test des entiers, on pourra imaginer facilement deux cas particuliers : 0 et un nombre négatif. Sans avoir besoin de code supplémentaire, ces comportements, une fois écrits en tant que critères, deviennent des tests :

Erreurs communes
Le BDD peut être un véritable outil tant pour la qualité du produit que pour la cohésion de l’équipe, mais il peut aussi poser des problèmes. Voici quelques erreurs communes qui peuvent rendre son adoption plus complexe, voire contreproductive.
Trop de phrases
C’est la première et probablement la plus fréquente des erreurs en BDD. Reprenons nos tests de tout à l’heure, mais en les écrivant un peu autrement.
Le besoin utilisateur couvert est exactement le même. Mais ici, au lieu de trois phrases, on en a sept. C’est une tendance naturelle lorsqu’on écrit des critères d’acceptation : on utilise un langage naturel, pour avoir des critères qui nous parlent. Pour que nos tests en BDD puissent fonctionner, il faut lutter contre cette tendance et s’imposer une discipline. Notre dictionnaire de phrases doit être aussi limité que possible, et chaque nouvel ajout doit être réfléchi.
Des phrases trop techniques
Cette erreur a tendance à se produire quand le BDD est mis en place par l’équipe de dev sans impliquer le PO. On peut alors voir apparaitre des phrases de ce type :
Ici, paradoxalement, on aura probablement autant voir moins de variété de phrases que dans du BDD classique : si on peut définir une variable, appeler une fonction et lire une variable, on aura probablement déjà une part non négligeable de nos tests. Mais les phrases seront inutilisables par le PO. Ce ne sont alors plus des éléments de communication au sein de l’équipe. On garde l’avantage de la réutilisation des tests, mais c’est un bénéfice secondaire.
J’ai expérimenté ce type de tests sur un gros projet. Le résultat est marginalement plus simple au début, mais dégénère vite et devient illisible. Nous l’avions implémenté sur un microservice, et nous avons décidé de ne pas étendre l’expérience aux autres.
Faire des tests unitaires
Cette erreur est plus générale. Nous séparons généralement les tests en trois catégories : tests unitaires, tests d’intégration et tests fonctionnels. J’ai tendance à préférer nettement les tests fonctionnels / tests d’acceptation, mais je comprends le besoin de faire des tests unitaires. Dans certains cas, c’est d’ailleurs nécessaire pour des parties de code qui ne peuvent pas être testées autrement, même si cela devrait logiquement être exceptionnel.
Néanmoins même dans ce cas, les tests unitaires doivent être implémentés de manière plus classique, via pytest par exemple. J’ai déjà vu des tests unitaires implémentés via du BDD : cela donnera forcément le même résultat que celui de l’erreur précédente.
Par définition, un test unitaire n’est pas lié directement à un critère d’acceptation : nous sommes donc obligés d’utiliser deux méthodes de test différentes si nous voulons utiliser deux types de tests différents.
Et vous, vous avez déjà testé le BDD ?