BDD

Behaviour Driven Development

Votre histoire

Un problème rencontré récemment

Quelque chose que vous auriez souhaité savoir plus tôt

Mettre le titre de l'histoire sur le post it

Conséquences sur engagements

A partir de quel moment cette décision n'était plus réversible ?

Quand est ce que le problème a été remonté ?

Quel a été le coût ?

Mauvaise information communiquée à un client externe ?

Deadline non respectée ?

Perte financière ?

Code écrit pour rien ?

Découverte délibérée

Comment auriez vous pu avoir l'information manquante

A qui auriez vous pu parler ?

Où était l'information

Comment auriez vous pu assouplir vos engagements ?

A priori

BDD n'est pas nécessairement un outil d'automatisation

BDD n'est pas associée aux tests bout en bout

BDD n'est pas associée aux tests sélénium

BDD n'est pas un outil

Avoir les conversations est plus important que les écrire ou les automatiser - Liz Keogh

Quelques repères historiques

Black box testing (Weinberg and Gause, 1989)

Exemples automatisés (Ward Cunningham, 1996)

DDD (Eric Evans, 2004)

TDD

1995: Ward Cunningham & Kent Beck

  1. Red: Écrire un test qui va échouer car l'implémentation n’existe pas encore (Tester le test)
  2. Green: Écrire l'implémentation utile la plus simple possible qui va faire passer les tests.
  3. Refactor: Supprimer la duplication. Améliorer le design.

TDD

Les 3 règles (Bob Martin, 2005):

Il est interdit d'écrire du code de production à moins que cela soit dans le but de faire passer un test en échec.
Il est interdit d'écrire plus que ce qui est nécessaire d'un test unitaire afin qu'il entre en échec; les échecs de compilations comptent pour des échecs.
Il est interdit d'écrire plus que ce qui est nécessaire du code de production afin de faire passer le test en échec.

TDD

Spécifications des interactions

Outil de design interne et externe incrémental

Écrites par les programmeurs

Pour les programmeurs

L'apprentissage du test

J'écris mon code en premier puis les tests
Les tests me permettent de vérifier que mon implémentation est correcte

L'apprentissage du test

Mes tests sont un filet de sécurité
Je peux modifier mon code avec confiance

L'apprentissage du test

Si j'écris mes tests avant l'implémentation alors je finis par écrire moins de code
De plus j'arrive à écrire un code plus facilement testable ce qui améliore mon design
Cette manière de travailler permet de concentrer mon attention sur la tache en cours

L'apprentissage du test

Avec le temps qui passe mes tests me servent de documentation

L'apprentissage du test

Écrire des tests revient à designer/spécifier l'API publique que je souhaiterais avoir
J'organise mon travail en commençant sur une phase de réflexion

L'apprentissage du test

En écrivant ces spécifications je spécifie le comportement attendu entre l'objet que je spécifie et ses collaborateurs

Mi-2003: De TDD à BDD

Par où commencer ?
Que faut-il tester ?
Comment appeler les tests ?
Que faut-il ne pas tester ?
Mais...les tests...c'est pour les testeurs !!!

Mi-2003: De TDD à BDD

Les noms des méthodes de test doivent être des phrases


import junit.framework.*;

	public class TestMath extends TestCase {

	  public void testAdd() { 
	        int num1 = 3; 
	        int num2 = 2; 
	        int total = 5; 
	        int sum = 0; 
	        sum = Math.add(num1, num2); 
	        assertEquals(sum, total); 
	  } 
	} 
						

import junit.framework.*;

	public class TestMath extends TestCase {

	  public void testAddingTwoNumberReturnTheirSum() { 
	        int num1 = 3; 
	        int num2 = 2; 
	        int total = 5; 
	        int sum = 0; 
	        sum = Math.add(num1, num2); 
	        assertEquals(sum, total); 
	  } 
	} 
						

Mi-2003: De TDD à BDD

Hypothèse de Sapir-Whorf/PNL

Les mots et les langages influent sur notre pensée

Introduction du mot "should" à la place de "test"

Le test se lit maintenant comme une spécification


import junit.framework.*;

public class TestTimer {
    public void testStartStop() throws Exception {
        Timer timer = new Timer();
        timer.start();

        Thread.sleep(10);
        timer.stop();

        assertTrue(timer.elapsedTimeMillis() > 0);
    }
} 
						

public class TimerSpec {
    public void shouldMeasureAPeriodOfTime() throws Exception {
        Timer timer = new Timer();
        timer.start();

        Thread.sleep(10);
        timer.stop();

        Verify.that(timer.elapsedTimeMillis() > 0);
    }
}
						

Mi-2003: De TDD à BDD

Avantages de "should"

Permet de nommer facilement les méthodes de test

Permet d'appliquer SRP

Permet de remettre en cause les tests

Aide à comprendre les rapports de tests

Début 2004: Gherkin

Tout cela ressemble fortement à de l'analyse...

Scénario: Effectuer un retrait avec succès
# Le contexte
Etant donné que je possède '100€' sur mon compte 
# Les événements
Quand je demande '20€' 
# Le résultat attendu
Alors '20€' doivent être distribués 
					

2005-2009: Feature injection, Outside In, pull based

Le développement est tiré par le besoin

Tout artefact existe car il provient d'un besoin plus haut dans le système

Permet de limiter le travail en cours

2007: SDD

Joshua Kerievsky (Refactoring to Patterns)

Communities that do StorytestDrivenDevelopment (SDD) work collaboratively on storytests. A domain expert may write some storytest details on a whiteboard while a QA person looks on and asks questions . Next, developers collaborate with the QA person and domain expert to understand and then automate the storytest. Lots of dialogue between members of the customer and developer communities happens throughout this process.

2009: Dan's long definition

BDD is a second-generation, outside-in, pull-based, multiple-stakeholder, multiple-scale, high-automation, agile methodology.It describes a cycle of interactions with well-defined outputs, resulting in the delivery of working, tested software that matters.

Second-generation

Comment tester ?
Comment documenter ?

Outside-in and pull based

Inspiré de lean

Développement tiré par le besoin

Besoin exprimé collaborativement sous forme d'exemples

On produit que ce qui est nécessaire

On produit quand c'est nécessaire

Agile

Itérations

Équipes multi-compétentes

Travail en tranches

High-Automation

Outillage

Vérification automatisée

Feedback sur travail en cours

Multiple stake holder (Kaizen)

Pousser la collaboration sur les 3 axes:

Métier

Technique

Personnes et les processus

Multiple scale

2009-2012: Specs par l'exemple

Standardiser ATDD,BDD,TDR,Example Driven Development,Story Testing Driven Development, Executable specifications

The fact that the same practices have so many names reflects the huge amount of innovation in this field at the moment. It also reflects the fact that the practices described in this book impact the ways teams approach specifications, development, and testing. To be consistent, I had to choose one name. I settled on Specification by Example*.

*Terme créé originellement par M.Fowler, 2002

Processus de développement classique

La communication

Ambiguïtés

Il a trouvé un avocat

Amphibologie

Elle est sortie en pleurant du café

Illusions

Comment communiquer ?

Comment le client l'a expliqué

Comment le chef de projet l'a compris

Comment l'analyste l'a conçu

Comment les développeur l'ont implémenté

Ce que les testeurs ont reçu

Comment les commerciaux l'ont décrit

Comment le projet a été documenté

Ce que la production a installé

Ce que le client a été facturé

Le support client qui a été fourni

Comment le marketing la vendu

Ce dont le client avait vraiment besoin

Optimisons au mieux le rôle de chacun

Je possède la vision du produit, connaît les conditions d'utilisations normales, réponds aux questions.
Je clarifie le besoin et vérifie la faisabilité technique (implem+automat)
Je sais où appuyer pour que ça fasse mal.

BDD comme processus de développement

Les individus et les échanges plutôt que les processus et les outils

Comment communiquer ?

Nous voulons augmenter le nombre de commandes. Nous allons donc accorder 10% de remises sur toutes les premières commandes.
public void CalculateDiscount(Order order){ if(order.Customer.IsNew) order.FinalAmount = Math.Round(order.Total*0.9); }
Register as "newuser" Go to "/catalog/search" Enter "ISBN-0955683610 Click "Search" Click "Add to cart" Click "View Cart" Verify "Subtotal" is "30"

Comment communiquer ?

Trouver un langage commun (DDD)

qui s'abstrait de la technologie

le QUOI avant le COMMENT

Supprimer la différence d’impédance entre BA/DEV/Test

le même langage à tous les niveaux

Apprendre ensemble/Découvrir ensemble le comportement de l'application

Processus ayant pour but d'arriver à une vision commune

S'exprimer en Gherkin

						
Etant donné un utilisateur qui n’a jamais commandé
Quand l’utilisateur met un livre dans son panier
Alors il faut lui accorder une remise de 10% sur le montant total du panier
						
					

Phase préparatoire

Réalisée avant l'atelier

Avec responsable métier, analystes

Sortir les premiers exemples d'utilisation

Le but est de préparer les futures discussions

Préparation de la session

L'idéal: 1 dev, 1 testeur, 1 BA

Rotations de paires selon maturité

Idéalement une personne spécialisée dans le domaine de la fonctionnalité

Acteurs préparés à l'avance

Noter une version "allégée" des scénarios

Equipe entière selon maturité

Les questions à se poser pour déterminer la valeur


Afin de 'valeur'
En tant que 'role'
Je veux 'fonctionnalité'
					

Comment cela doit fonctionner ?

Pourquoi cela doit il fonctionner comme cela ?

Qui a besoin de cette fonctionnalité

Que se passerait il si cette fonctionnalité était enlevée?

Quelle est la valeur pour les utilisateurs

Les 5 pourquoi

Deliberate discovery

Trouver des nouveaux scénarios à travers la collaboration et le brainstorming


Etant donné 'essayer de trouver différents contextes'
Quand 'utilisation de la fonctionnalité'
Alors 'essayer de trouver des vérifications alternatives'
						

Découvrir ce que nous ne savons pas

Découvrir les choses critiques qui pourraient être oubliés

Processus d'apprentissage collaboratif

Exemple déroulement session

Nous voulons proposer aussi à nos client la livraison à domicile
Existe il des cas où il ne faut pas proposer la livraison à domicile ?
Oui il ne faut pas la proposer pour les adresses de livraisons qui ne se situent pas sur paris
D'accord, il faut donc proposer cette option uniquement pour les adresses ayant pour code postal 75XXX

Exemple déroulement session

Attention, certains pays comme l’Italie ont des codes postaux de la forme 75XXX, mais bien sûr il ne faut pas proposer cette option en italie
OK, je pense qu'il faudrait écrire un scénario supplémentaire pour ce cas-ci afin de montrer que l'option n'est disponible qu'en France et que pour les code postaux situés sur Paris

Exemple déroulement session

Nous voulons offrir la livraison gratuite pour certains produits comme certains livres par exemple
Est-ce que cette livraison gratuite est disponible qu'importe le lieu de livraison ?
En effet il ne faut pas proposer la livraison à domicile en dehors de la France.
Que se passe-t-il si j’achète un livre avec livraison gratuite et un sans livraison gratuite ?
Dans ce cas on bénéficie toujours de la livraison gratuite pour l'ensemble des livres

Exemple déroulement session

Que se passe-t-il si je commande un livre et un frigo, certainement la livraison ne pas plus être gratuite non ?
Mhmmm nous n'avons pas pensé à ce cas, je dois en discuter et je reviendrais vers vous concernant ce scénario.

Deliberate discovery, examples

							
Etant donné que je possède 100€ sur mon compte
Quand je demande 20€
Alors 20€ doivent être distribués
							
						
							
Etant donné que je possède 100€ sur mon compte
Quand je demande 20€
Alors je dois récupérer ma carte
							
						
							
Etant donné que je possède 100€ sur mon compte
Quand je demande 20€
Alors mon compte doit être débité de 20€
							
						

Avantages de Gherkin

Un exemple concret vaut mieux qu'une explication générale et abstraite

Les clients ne doivent pas pouvoir saisir de numéro de carte bleue invalide

Laisse des questions en suspens: Qu'est-ce qu'un numéro de carte invalide ? Comment l'utilisateur doit être notifié ?

Une meilleure version:

		 	
Scénario: saisie de numéro de carte bleue incorrect
Etant donné que le client a saisit un numéro de carte bleu avec une longueur inférieure à 16 chiffres
Quand il valide sa saisie
Alors un message doit lui indiquer que sa saisie est incorrecte
		 	
		 

Avantages de Gherkin

Simple et souple

Gherkin n'impose que les mots clés Given/When/Then

Tout le reste peut être écrit en langage naturel !

Avantages de Gherkin

Écriture et lecture à la portée de tous

Peuvent être remises en cause

Avantages découlant de l'utilisation de BDD

Implication du métier en leur offrant une meilleure transparence sur l'implémentation des fonctionnalités

Ludique et facilite le brainstorming

Permet d'améliorer l'esprit d'appropriation de l'équipe face au produit car on va spécifier ensemble

Permet de simuler la future utilisation de la fonctionnalité et dans voir les limites

Permet de découvrir de nouvelles options avant de s'engager dans une voie

Responsabilisation et appropriation

L'équipe entière s'investit dans

La qualité du produit

L'automatisation des spécifications

La création d'une application facile à tester

La documentation de l'application

Avantages découlant de l'utilisation de BDD

Working software over comprehensive documentation

Une documentation de l'application toujours à jour !

Des spécification versionnées grâce au contrôle de source

Avantages découlant de l'utilisation de BDD

Donne un point de départ à TDD + lean code + Feature injection + YAGNI + KISS

Création d'un langage omniprésent (DDD, spec, code, test, conversations)

Effets secondaires de BDD

Servent de filet anti-régression

Permet de faciliter le refactoring car test boite noire

Donne un point de départ à TDD + lean code + Feature injection + YAGNI + KISS

Ruby Cucumber

.NET SpecFlow

Cucumber JVM

Feature: Hello World
  Scenario: Say hello
    Given I have a hello app with "Howdy"
    When I ask it to say hi
    Then it should answer with "Howdy World"


public class HelloStepdefs {
    private Hello hello;
    private String hi;

    @Given("^I have a hello app with \"([^\"]*)\"$")
    public void I_have_a_hello_app_with(String greeting) {
        hello = new Hello(greeting);
    }

    @When("^I ask it to say hi$")
    public void I_ask_it_to_say_hi() {
        hi = hello.sayHi();
    }

    @Then("^it should answer with \"([^\"]*)\"$")
    public void it_should_answer_with(String expectedHi) {
        assertEquals(expectedHi, hi);
    }
}

Améliorer la lisibilité à l'aide des tables

						
Etant donné le produit 'Baskets' avec un prix de '50' euros et un poids de '300' g
Et le produit 'Jeans' avec un prix de '60' euros et un poids de '200' g
Et le produit 'T-shirt' avec un prixd '20 euros' et un poids de '50' g
						
					

Améliorer la lisibilité à l'aide des tables

						
Etant donné les produits:
|Nom    |Prix (euros)|Poids (g)|
|Baskets|50          |300      |
|Jeans  |60          |200      |
|T-shirt|20          |50       |
						
					

Patrons de scénarios

						
Fonctionnalité: Retrait d’un montant fixe
Le menu de retrait contient plusieurs montants
fixes afin que le client puisse retirer rapidement
Scénario:Retrait de 50€
Etant donné que je possède 500€ sur mon compte
Quand je retire 50€
Alors je dois recevoir 50€
Et mon compte doit posséder un solde de 450€

Scénario:Retrait de 100€
Etant donné que je possède 500€ sur mon compte
Quand je retire 100€
Alors je dois recevoir 100€
Et mon compte doit posséder un solde de 400€

Scénario:Retrait de 200€
Etant donné que je possède 500€ sur mon compte
Quand je retire 200€
Alors je dois recevoir 200€
Et mon compte doit posséder un solde de 300€
						
					

Patrons de scénarios

						
Fonctionnalité: Retrait d’un montant fixe
Le menu de retrait contient plusieurs montants
fixes afin que le client puisse retirer rapidement
Scénario:Retrait
Etant donné que je possède '<solde>'€ sur mon compte
Quand je retire '<retrait>'€
Alors je dois recevoir '<distribué>'€
Et mon compte doit posséder un solde de '<restant>'€

Examples:
|solde|retrait|distribué|restant|
|500  |50     |50       |450    |
|500  |100    |100      |400    |
|500  |200    |200      |300    |
						
					

Scénarios à tables multiples

							
Etant donné que j’essaie de créer un compte avec le mot de passe '<Mot de passe>'
Alors je devrais être notifié que le mot de passe est '<Validité>'

Examples: Trop court
Les mots de passe inférieurs à 4 caractères sont invalides
| Mot de passe | Validité |
| abc 		   | invalide |
| ab1          | invalide |

Examples: Lettres et chiffres
Les mots de passe doivent contenir des lettres et des chiffres
| Mot de passe | Validité |
| abc1         | valide   |
| abcd         | invalide |
| abcd1        | valide   |
							
						

Bonnes pratiques

Éviter les scénarios trop abstraits

						
Scénario: Montant total du panier
Etant donné un client avec 3 produits dans son panier
Alors il doit visualiser correctement le montant total

Scénario: Montant total du panier
Etant donné un client A
Et possédant un panier avec les produits B et C
						
					

Bonnes pratiques

Éviter les scénarios trop abstraits

						
Scénario: Montant total du panier
Etant donné un client avec les produits suivants dans son panier
|Nom du produit  |Prix unitaire(euros)|Quantité|
|PS3		     |250                 |1       |
|Prince of persia|50                  |1       |
Quand il consulte son panier flotant
Alors il doit visualiser un montant total de 300 euros
						
					

Mauvaises pratiques

Faire apparaître des ID techniques

						
Scénario: Montant total du panier
Etant donné les produits suivants:
  |Id|Produit         |Prix unitaire|
  |1 |PS3             |250          |
  |2 |Prince of persia|50           |
Et le client suivant
  |Id|Nom|
  |1 |John|
Et le panier suivant:
  |Id|ClientId|
  |1 |1       |
Et avec les articles suivants:
  |Id|PanierId|ArticleId|Quantité|
  |1 |1       |1        |1       |
  |2 |1       |2        |1       |
						
					

Bonnes pratiques

Lisibilité avant tout (scripts à bannir)

Ne pas exprimer les scénarios en terme d'UI

Découplé de l'UI afin de faciliter le changement

Sont généralement trop verbeux, ennuyants à lire et fragiles

Exprimez vos scénarios en terme métier

Bonnes pratiques

Éviter les tests workflow

=>Tester en terme d'UI ou de workflow masque l'intention, le lecteur doit refaire le chemin inverse

=>Le QUOI pas le COMMENT

Mauvaises pratiques

Se concentrer sur comment l'application doit réaliser la fonctionnalité

						
Scénario: Les utilisateurs non connectés doivent être redirigés vers le formulaire de connexion
Etant donné l’utilisateur 'Pierre'
Et ayant pour adresses email 'pierre@yahoo.com'
Et ayant le mot de passe 'passw0rd'
Quand l’utilisateur visite la page 'http://localhost:5740/monsite'
Alors il doit être redirigé vers la page 'https://localhost:5740/monsite/login'
Quand il saisit le login 'pierre@yahoo.com' dans le champ '#login'
Et qu’il saisit le mot de passe 'passw0rd' dans le champ '#mdp'
Et qu’il valide le formulaire "#formLogin" de connexion
Alors il doit être redirigé vers la page 'http://localhost:5740/monsite/home'
						
					

Bonnes pratiques

Se concentrer sur ce que doit faire l'application et non pas comment elle le réalise

						
Scénario: Les utilisateurs non connectés doivent être redirigés vers le formulaire de connexion
Etant donné un utilisateur non connecté
Quand il essaie d’accéder à n’importe quelle page du site
Alors il doit être redirigé vers le formulaire de connexion

Scénario: Utilisateur ayant été redirigé vers le formulaire de connexion
Etant donné un utilisateur ayant été redirigé vers le formulaire de connexion
Quand il soumet ses identifiants
Alors il doit être redirigé vers la page dont il avait essayé d’accéder
						
					

Mauvaises pratiques

Ne pas prendre le temps de bien nommer les scénarios

						
Scénario: 100 euros
Etant donné que le client possède pour plus de 100 euros de produits
Quand il consulte son récapitulatif de panier
Alors il doit visualiser une réduction immédiate de 10% sur le montant total
						
					

Bonnes pratiques

Faire un résumé du scénario

						
Scénario: Accorder une réduction de 10% pour les paniers de plus de 100 euros
Etant donné que le client possède pour plus de 100 euros de produits
Quand il consulte son récapitulatif de panier
Alors il doit visualiser une réduction immédiate de 10% sur le montant total
						
					

Permet de retrouver plus rapidement des scénarios d'intérêt

Permet par la suite d'aider à l'analyse des scénarios en échec

Tags: Retrouver ses scénarios

						
@nightly @web @summary @sprint10
Scénario: Accorder une réduction de 10% pour les paniers de plus de 100 euros
Etant donné que le client possède pour plus de 100 euros de produits
Quand il consulte son récapitulatif de panier
Alors il doit visualiser une réduction immédiate de 10% sur le montant total
						
					

Éviter de tester toutes les combinaisons

Partir du happy path

Explorer à partir de là

Ces scénarios pourront servir de bases pour une autre spec plus orienté vérification.

Les principes F.I.R.S.T

Fast

Independent

Repeatable

Self Validating

Timely

Bugs

Il n'y pas de bugs!

Mais que des scénarios oubliés !

Mauvaises pratiques

Écrire les scénarios en solo

Écrire les scénarios avec seulement BA et testeur puis catapultage sur le développeur

Les 3 acteurs doivent toujours arriver à une étape de collaboration

Afin de développer le langage/compréhension/vision commune

Mauvaises pratiques

Utiliser Specflow pour de simples TU


Feature: Stack

When a new stack is created
Then it is empty

When an element is added to the stack
Then that element is at the top of the stack

When a stack has N elements 
And element E is on top of the stack
Then a pop operation returns E
And the new size of the stack is N-1
				

describe Hash do
  before do
    @hash = Hash.new({:hello => 'world'})
  end
 
  it "should return a blank instance" do
    Hash.new.should == {}
  end
 
  it "hash the correct information in a key" do
    @hash[:hello].should == 'world'
  end
end
				

En savoir plus ?

Livres

Blogs

lizkeogh.com dannorth.net

Wiki

behaviordrivendevelopment.wikispaces.com

Attention

Pas que du bon sur le net!