Tutoriel de prise en main de Cucumber pour coder des tests Behavior Driven Development avec Java : recette aux concombres pour débutant

Isabelle BLASQUEZ

Ce tutoriel s'inspire de l'exemple Shakespeare du Kata Cucumber/Mockito de Sébastien Mosser.

Cucumber est un framework de tests pour le « Behavior Driven Development », initialement développé en « Ruby », mais proposant aujourd'hui différentes implémentations pour de nombreux autres langages de programmation. Le site de référence est : cucumber.io.

Dans l'écosystème « Java », Cucumber est aujourd'hui l'un des frameworks BDD les plus utilisés.

Comme tout framework adapté au BDD, Cucumber permet de transformer les scénarios d'une « story » (écrits sous forme d'exemples en langage naturel au format Gherkin) en tests java automatisés. Dans le principe, cette transformation est possible à l'aide du framework de tests JUnit. Chaque étape d'un scénario est implémentée comme une méthode Java, appelée step. Le lien entre la description textuelle de l'étape et le code Java de la step est réalisé via des annotations.

Dans ce tutoriel, nous verrons comment :

- Installer le plug-in Cucumber-Eclipse ;

- Mettre en place votre premier projet Cucumber :

- 1. Créer un projet Maven,

- 2. Configurer le pom.xml pour Cucumber,

- 3. Décrire le comportement en langage naturel (.feature),

- 4. Configurer le lanceur de tests,

- 5. Implémenter le code de test des steps (méthodes java),

- 6. Implémenter le code métier de l'application.

Mais aussi, comment :

- Paramétrer les steps à l'aide d'expressions régulières ;

- Alléger la lecture d'un scénario (AndetBut) ;

- Paramétrer un scénario ;

- Factoriser des scénarios ;

- Paramétrer le lanceur de test à partir de@CucumberOptions ;

- Produire un beau rapport à l'aide du plug-in cucumber-reporting ;

- Remarques complémentaires.

Pour réagir à ce tutoriel, un espace de dialogue vous est proposé sur le forum Commentez .

- Titre : Tutoriel de prise en main de Cucumber pour coder des tests Behavior Driven Development avec Java : recette aux concombres pour débutant

- Auteur : Isabelle BLASQUEZ

- Parution : 10 octobre 2018

- Licence : Copyright ® 2018 Isabelle BLASQUEZ. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.

Sommaire

- I. Installer le plug-in Cucumber-Eclipse

- II. Mettre en place votre premier projet Cucumber

- II-A. Créer un projet Maven

- II-B. Configurer le pom.xml pour Cucumber

- II-C. Décrire le comportement en langage naturel (.feature dans src/test/resources)

- II-D. Configurer le lanceur de test (dans src/test/java)

- II-D-1. Création d'un fichier RunCucumberTest.java dans un package dojo de src/test/java

- II-D-2. Exécution du lanceur de test (RunCucumberTest.java)

- II-E. Implémenter le code de test des steps (méthodes java) (dans src/test/java)

- II-E-1. Le squelette des steps issu du rapport de tests de la console

- II-E-2. La configuration du lanceur de test pour une step dite PENDING (option strict)

- II-E-3. L'implémentation des steps en Java pour produire le comportement attendu

- II-E-3-a. Zoom sur la première step Java

- II-E-3-b. Une implémentation possible pour la deuxième step

- II-E-3-c. Une implémentation possible pour la troisième step

- II-F. Implémenter le code métier de l'application

- III. Paramétrer les steps à l'aide d'expressions régulières

- III-A. Paramétrer les steps Java

- III-A-1. Paramétrer la step @Given

- III-A-2. Paramétrer la step @When

- III-A-3. Paramétrer la step @Then

- III-B. Écriture d'un nouveau scénario à l'aide du plug-in Cucumber-Eclipse

- III-B-1. Première étape du scénario (Given)

- III-B-2. Deuxième étape du scénario (When)

- III-B-3. Troisième étape du scénario (Then)

- III-C. Exécution du nouveau scénario

- IV. Alléger la lecture d'un scénario (And et But)

- V. Paramétrer un scénario

- V-A. Un premier scénario paramétré…

- V-B. Un autre scénario paramétré…

- VI. Factoriser des scénarios

- VII. Paramétrer le lanceur de test à partir de @CucumberOptions

- VII-A. L'option feature pour indiquer où se trouvent les scénarios à tester

- VII-B. L'option monochrome pour améliorer la lisibilité des scénarios dans la console

- VII-C. L'option plug-in pour formater et générer un rapport de tests

- VII-C-1. Formater avec pretty

- VII-C-1-a. Générer un rapport au format HTML natif avec l'option html

- VII-C-1-b. Générer un rapport au format XML natif avec l'option junit

- VII-C-1-c. Générer un rapport au format JSON natif avec l'option json

- VIII. Produire un beau rapport à l'aide du plug-in cucumber-reporting

- VIII-A. Installer le plug-in cucumber-reporting

- VIII-B. Configurer le plug-in cucumber-reporting

- VIII-B-1. S'assurer de générer un fichier json

- VIII-B-1-a. S'assurer que les rapports soient générés APRÈS les tests

- VIII-B-1-b. Paramétrer le plug-in

- VIII-C. Visualiser les rapports générés par le plug-in cucumber-reporting

- VIII-C-1. Accéder aux rapports générés (cucumber-html-reports)

- VIII-C-1-a. Visualiser les différents rapports générés par cucumber-reporting

- IX. Remarques complémentaires

- IX-A. Tout savoir sur le Gherkin…

- IX-B. Des stories en français (Internationalisation)

- IX-C. Un petit coup d'œil sur des projets utilisant Cucumber

- IX-D. Écrire du bon gherkin : attention aux antipatterns !

- X. Références

- XI. Remerciements

I - Installer le plug-in Cucumber-Eclipse

Cucumber-Eclipse est un plug-in Eclipse qui permet d'écrire et d'exécuter les scénarios Cucumber directement dans l'IDE facilitant ainsi leur automatisation.
La documentation en ligne de ce plug-in est disponible sur : https://github.com/cucumber/cucumber-eclipse. Comme nous le verrons un peu plus loin, ce plug-in propose entre autres une coloration syntaxique, une assistance lors de l'écriture des scénarios, et quelques autres fonctionnalités consultables sur ce wiki.

Pour installer ce plug-in dans Eclipse, utiliser le menu Help → Install New Software… et indiquer l'adresse de site suivante : https://cucumber.io/cucumber-eclipse//update-site ou rendez-vous dans l'Eclipse Market Place.

Redémarrer Eclipse.

II - Mettre en place votre premier projet Cucumber

II-A - Créer un projet Maven

Créez un projet maven que vous appellerez, par exemple, cucumber_demo.

II-B - Configurer le pom.xml pour Cucumber

Mettre à jour votre pom.xml avec les trois dépendances suivantes :

- la première pour pouvoir utiliser Cucumber. Nous avons choisi une dépendance classique : cucumber-java (pas d'utilisation de lambda dans ce tutoriel) comme indiqué dans la partie Installation de la documentation Cucumber spécifique à Java ;

- les deux dépendances suivantes cucumber-junit et junit pour pouvoir exécuter les scénarios Cucumber dans JUnit à l'aide du JUnit Runner comme indiqué dans la partie Checking Assertions de la documentation de Cucumber. Chaque étape de scénario, considérée alors comme un test spécifique, pourra ainsi être directement visualisée dans la vue JUnit de l'IDE.

1. <dependencies>

2. <dependency>

3. <groupId>io.cucumber</groupId>

4. <artifactId>cucumber-java</artifactId>

5. <version>3.0.2</version>

6. <scope>test</scope>

7. </dependency>

8. <dependency>

9. <groupId>io.cucumber</groupId>

10. <artifactId>cucumber-junit</artifactId>

11. <version>3.0.2</version>

12. <scope>test</scope>

13. </dependency>

14. <dependency>

15. <groupId>junit</groupId>

16. <artifactId>junit</artifactId>

17. <version>4.12</version>

18. <scope>test</scope>

19. </dependency>

20. </dependencies>

Une fois, le pom.xml modifié, n'oubliez pas de relancer Maven -> Update Project…

II-C - Décrire le comportement en langage naturel (.feature dans src/test/resources)

Créez un nouveau Source Folder que vous appellerez src/test/resources. Créez un fichier cocktail.feature dans un package dojo de src/test/resources.

Le plug-in Cucumber-Eclipse reconnaît l'extension .feature et vous remplit automatiquement ce fichier en vous montrant différentes manières d'écrire un scénario.

Effacez le contenu de ce fichier, ne gardez que la première ligne dans laquelle vous pouvez ajouter vos noms et prénoms, par exemple #Author: Isabelle BLASQUEZ

Recopiez ensuite dans ce fichier le récit de la story suivante et enregistrez-le :

1. Feature: Cocktail Ordering

3. As Romeo, I want to offer a drink to Juliette so that we can discuss together (and maybe more).

5. Scenario: Creating an empty order

6. Given Romeo who wants to buy a drink

7. When  an order is declared for Juliette

8. Then  there is no cocktail in the order

Dans Cucumber, une story est composée de scénarios et chaque scénario est composé d'étapes. La story est (d)écrite en Gherkin dans un fichier .feature dans lequel on trouve :

- le titre de la story introduit par le mot clé Feature ; Feature: <Titre de la fonctionnalité>

- Un descriptif (optionnel) (qui ne sera pas interprété par Cucumber) permettant par exemple, de résumer la story à l'aide du template As..., I want to..., so that... et/ou de noter toute autre information utile à connaître ;

- les scénarios de la story :

- Chaque scénario est introduit par le mot clé Scenario. Ce mot clé peut être suivi ou non d'un titre qui décrit explicitement le critère d'acceptation de la story associée à ce scénario,

- Un scénario étant un exemple concret qui illustre une règle métier, il est composé de plusieurs étapes. Les différentes étapes d'un scénario sont décrites à partir des trois principaux mots clés : Given, When et Then suivant la place et le rôle qu'elles occupent dans le scénario :

- Given décrit les conditions initiales du scénario, c.-à-d. le contexte dans lequel va se dérouler le scénario,

- When décrit une action effectuée par un utilisateur, c.-à-d. un événement qui va réellement déclencher le scénario,

- Then décrit le comportement attendu, ce qui devrait se produire lorsque les conditions initiales sont remplies et l'action est effectuée.

Pour en savoir plus, la documentation de Cucumber propose deux rubriques sur les étapes (steps) Given-When-Then consultables ici et là.

Cucumber propose quelques mots clés supplémentaires comme Background, And, But, Scenario Outline et Examples que nous verrons un peu plus loin.

Remarque : une présentation complète de la grammaire utilisée par Cucumber est consultable dans la rubrique Gherkin Syntax de la documentation de Cucumber.

II-D - Configurer le lanceur de test (dans src/test/java)

Le lanceur de test permet de configurer l'environnement de test des scénarios.

II-D-1 - Création d'un fichier RunCucumberTest.java dans un package dojo de src/test/java

Implémenter ce fichier de manière qu'il devienne le lanceur des tests Cucumber :

1. package dojo;

3. import cucumber.api.junit.Cucumber;

4. import org.junit.runner.RunWith;

6. @RunWith(Cucumber.class)

7. public class RunCucumberTest { }

L'annotation @RunWith(Cucumber.class) permet d'exécuter les scénarios Cucumber dans JUnit à l'aide du JUnit Runner.

Remarque : pour l'instant, la configuration du lanceur de test est minimale. La configuration peut être personnalisée via des options de configuration prédéfinies et consultables dans la rubrique Running Cucumber du manuel de référence. Ces options seront transmises via l'annotation @CucumberOptions : nous ajouterons certaines options par la suite.

II-D-2 - Exécution du lanceur de test (RunCucumberTest.java)

Pour exécuter les scénarios du fichier .feature, il suffit désormais d'exécuter le lanceur de test RunCucumberTest comme un simple fichier JUnit via la commande habituelle (Run As -> JUnit Test).

Il ne vous reste donc plus qu'à lancer vos scénarios et consulter la console.

Le lanceur de test fait le mapping entre les étapes des scénarios écrites de manière naturelle (fichier .feature) et les méthodes Java implémentant ces étapes. Les étapes Java sont appelées des steps et sont définies grâce à des annotations spécifiques : @Given, @When, @Then.

À ce point du tutoriel, le fichier contenant les steps n'existe pas encore.

C'est pourquoi, le rapport de tests dans la console propose, pour chaque étape du fichier .feature, un squelette de step (annoté et paramétré) qu'il ne reste plus qu'à implémenter pour réaliser le mapping entre les scénarios Cucumber et le code métier Java.

Remarque : si vous ne voyez pas le rapport de tests dans la console, c'est que vous n'avez sûrement pas enregistré le fichier cocktail.feature au bon endroit, c.-à-d. dans un package dojo du source folder src/test/resources.

II-E - Implémenter le code de test des steps (méthodes java) (dans src/test/java)

Créer un fichier CocktailSteps.java dans un package dojo de src/test/java.

II-E-1 - Le squelette des steps issu du rapport de tests de la console

Implémenter ce fichier de steps en copiant/collant le rapport de tests fourni par la console (moins fastidieux et plus sûr que d'écrire le mapping à la main).

Ajouter ensuite les import nécessaires à une bonne compilation afin d'obtenir un code similaire au suivant :

1. package dojo;

3. import cucumber.api.PendingException;

4. import cucumber.api.java.en.Given;

5. import cucumber.api.java.en.Then;

6. import cucumber.api.java.en.When;

8. public class CocktailSteps {

9. @Given("Romeo who wants to buy a drink")

10. public void romeo_who_wants_to_buy_a_drink() {

11. // Write code here that turns the phrase above into concrete actions

12. throw new PendingException();

13. }

14. @When("an order is declared for Juliette")

15. public void an_order_is_declared_for_Juliette() {

16. // Write code here that turns the phrase above into concrete actions

17. throw new PendingException();

18. }

19. @Then("there is no cocktail in the order")

20. public void there_is_no_cocktail_in_the_order() {

21. // Write code here that turns the phrase above into concrete actions

22. throw new PendingException();

23. }

24. }

Chaque step commence par une annotation spécifique : @Given ou, @When ou @Then.

Pour que le mapping existe entre la step (.java) et l'étape d'un scénario (.feature), la valeur de l'annotation Java doit contenir la phrase décrivant l'étape du scénario à quelques caractères spéciaux près.
Pour plus de renseignements, consultez la rubrique Step Définitions du manuel de référence.

II-E-2 - La configuration du lanceur de test pour une step dite PENDING (option strict)

Pour l'instant chaque step lance juste une PendingException.
On dit qu'une step est PENDING lorsque le mapping entre le langage naturel et le code n'a pas encore été réalisé.

Exécuter le lanceur de test et consulter la vue JUnit.

Vous remarquerez que tous les tests passent au VERT, et que la console indique la présence de cucumber.api.PendingException ce qui signifie qu'une implémentation des steps est attendue.

Il est possible de faire en sorte que les tests soient au ROUGE lorsqu'une ou plusieurs steps restent à implémenter. Pour cela il est nécessaire de configurer le lanceur de test RunCucumberTest à l'aide de l'annotation @CucumberOptions et de l'option strict positionnée à true.

Ajouter l'annotation @CucumberOptions(strict = true) à la classe RunCucumberTest :

@RunWith(Cucumber.class)
@CucumberOptions(strict = true)
public class RunCucumberTest { }

Exécuter le lanceur de test.
Cette fois-ci, une barre ROUGE apparaît, car le premier test est en échec (la step n'a pas encore été implémentée).

II-E-3 - L'implémentation des steps en Java pour produire le comportement attendu

Il est maintenant nécessaire d'implémenter chaque step de manière qu'elle produise le comportement attendu du scénario et puisse ainsi être exécutée en Java.

II-E-3-a - Zoom sur la première step Java

Par exemple, la première étape du scénario : Given Romeo who wants to buy a drink devient exécutable en Java, dès lors qu'on lui associe le code suivant qui est une traduction possible de manière algorithmique du comportement attendu :

1. public class CocktailSteps {

2. private Order order;

3. @Given("Romeo who wants to buy a drink")

4. public void romeo_who_wants_to_buy_a_drink() {

5. order = new Order();

6. order.declareOwner("Romeo");

7. }

8. //...

9. }

Remarque : ceci est une proposition pour rendre l'étape Given Romeo who wants to buy a drink exécutable, donc une proposition de conception pour notre application de cocktails. On dit qu'ici le développement est dirigé par le comportement (Behavior Driven Developement), dans le sens où le comportement de la story (décrit au travers des différentes étapes de son scénario) permet de faire émerger une API publique pour l'application.

Cette première step a ainsi permis de faire apparaître une classe Order et sa méthode declareOwner (qu'il ne restera plus qu'à implémenter pour faire passer la step au VERT…)

II-E-3-b - Une implémentation possible pour la deuxième step

1. public class CocktailSteps {

2. //...

3. @When("an order is declared for Juliette")

4. public void an_order_is_declared_for_juliette() {

5. order.declareTarget("Juliette");

6. }

7. //...

8. }

II-E-3-c - Une implémentation possible pour la troisième step

1. import static org.junit.Assert.*;

2. import java.util.List;

4. public class CocktailSteps {

5. //...

6. @Then("there is no cocktail in the order")

7. public void there_is_no_cocktail_in_the_order() {

8. List<String> cocktails =  order.getCocktails();

9. assertEquals(0, cocktails.size());

10. }

11. }

Implémenter les trois steps avec le code proposé précédemment.

Supprimer les erreurs de compilation en vous aidant de votre IDE, pour créer automatiquement (en gardant pour l'instant l'implémentation vide par défaut proposée par l'IDE) :

- une classe Order dans le package dojo de src/main/java ;

- et ses méthodes : declareOwner, declareTarget et getCocktails.

Le scénario Gherkin du fichier .feature est désormais transformé en code Java exécutable.
L'assertEquals de la step @Then montre bien que ce scénario est en fait transformé en un test appelé test d'acceptance (puisqu'on se situe au niveau de la story donc des exigences du client).

Exécuter le scénario via RunCucumberTest revient à exécuter ce test.

Essayez d'exécuter le fichier RunCucumberTest pour voir ce qui se passe. Que constatez-vous ? La step @Then échoue : c'est normal car pour le moment nous n'avons rien implémenté…

II-F - Implémenter le code métier de l'application

L'idéal dans un développement agile est bien sûr d'implémenter le code métier en TDD.

Pour ce tutoriel, contentez-vous de recopier l'implémentation suivante pour votre classe Order :

1. package dojo;

3. import java.util.ArrayList;

4. import java.util.List;

6. public class Order {

7. private String from;

8. private String to;

9. private List<String> contents = new ArrayList<String>();

11. public void declareOwner(String romeo) {

12. this.from = romeo ;

13. }

15. public void declareTarget(String juliette) {

16. this.to = juliette ;

17. }

18. public List<String> getCocktails() {

19. return contents;

20. }

21. }

Exécutez le fichier RunCucumberTest. Que constatez-vous ? La step @Then est au VERT : le Scenario: Creating an empty order est exécuté par le programme Java avec succès.
Ce scénario est donc devenu une spécification exécutable, puisque l'exécuter revient maintenant à tester automatiquement (et donc à exécuter) le code métier.

En résumé : la mise en place de votre premier projet Cucumber s'est faite en plusieurs étapes reprises visuellement sur la figure suivante (anciennement disponible sur le site cukes.info devenu depuis cucumber.io)

Ainsi, outre créer un projet Maven et configurer le pom.xml pour Cucumber, la mise en place de tests fonctionnels automatisés a nécessité :

1. De décrire le comportement en langage naturel (.feature) ;

2. D'implémenter le code de test des steps (méthodes java) ;

3. D'implémenter le code métier de l'application ;

4. et 5. D'exécuter les tests jusqu'à ce qu'ils passent au VERT ! sans oublier bien sûr de configurer le lanceur de tests (RunCucumberTest.java).

III - Paramétrer les steps à l'aide d'expressions régulières

Pour l'instant, notre scénario met uniquement en scène Roméo et Juliette. Mais ne pourrait-on pas imaginer un nouveau scénario (nouvel exemple) où Tom souhaiterait prendre un verre avec Jerry ?

1. Scenario: Creating another new empty order

2. Given Tom who wants to buy a drink

3. When  an order is declared for Jerry

4. Then  there is no cocktail in the order

On ne vous demande pas d'écrire ce scénario pour le moment, juste d'en prendre connaissance et de constater que ce scénario reprend les étapes du scénario précédent à deux paramètres près : Tom et Jerry au lieu de Roméo et Juliette. Il soulève ainsi la question de savoir comment paramétrer les steps @Given, @When et @Then dans le code Java afin d'éviter la duplication de code…

Cucumber permet cela en proposant l'utilisation d'expressions régulières (regex) dans les steps Java pour matcher (détecter) un motif dans la description textuelle d'une étape. Par exemple :

- l'expression (.*) permettra de matcher un string ;

- l'expression (\\d+) permettra de matcher un entier ;

Remarques :

- un exemple d'expression régulière concernant les entiers est d'ailleurs donné dans la partie Steps Définitions du manuel de référence Cucumber (veillez bien à choisir le langage Java qui devrait vous afficher : @Given("I have (\\d+) cukes in my belly") ;

- besoin d'un petit rappel sur les regex ? :

- une liste des expressions régulières Cucumber peut être consultée ici,

- une liste des expressions régulières avec l'API Regex de Java peut être consultée ici.

Pour la suite du tutoriel, nous allons donc commencer par remanier le code existant du scénario Roméo et Juliette en le paramétrant avant d'ajouter un nouveau scénario…

III-A - Paramétrer les steps Java

III-A-1 - Paramétrer la step @Given

Pour paramétrer le nom de la personne qui veut prendre un verre, il faut donc dans le code Java :

- ajouter l'expression (.*) à la place de Romeo dans l'annotation Given ;

- ajouter un paramètre de type String romeo dans la signature de la méthode ;

- passer le paramètre romeo dans la méthode declareOwner à la place de la valeur "Romeo".

Le code de la nouvelle step @Given devient donc :

1. @Given("(.*) who wants to buy a drink")

2. public void romeo_who_wants_to_buy_a_drink(String romeo) {

3. order = new Order();

4. order.declareOwner(romeo);

5. }

Modifier le code de la step @Given et exécuter RunCucumberTest afin de s'assurer que les tests passent toujours au VERT !

III-A-2 - Paramétrer la step @When

Paramétrer cette step revient à paramétrer le nom de la personne pour qui on commande un verre.

Paramétrer la step @When revient à écrire le code suivant :

1. @When("an order is declared for (.*)")

2. public void an_order_is_declared_for_Juliette(String juliette) {

3. order.declareTarget(juliette);

4. }

Modifier le code de la step @When et exécuter RunCucumberTest afin de s'assurer que les tests passent toujours au VERT !

III-A-3 - Paramétrer la step @Then

Paramétrer cette step revient à paramétrer le nombre de cocktails dans la commande.

En l'état actuel, il faut remanier à deux niveaux :

- dans l'étape textuelle du scénario (fichier cocktail.feature) : commencer par remplacer le no par 0 et rajouter un s à cocktails (en prévision de la « réutilisabilité » de cette étape par la suite) de manière à obtenir : Then there is 0 cocktails in the order ;

- dans la step @Then (fichier CocktailSteps.java) : paramétrer le nombre de cocktails comme un entier grâce à l'expression (\\d+) (et ne pas oublier de rajouter des s à cocktails) et utiliser le paramètre nbCocktails de manière à obtenir :

1. @Then("there is (\\d+) cocktails in the order")

2. public void there_is_nb_cocktails_in_the_order(int nbCocktails) {

3. List<String> cocktails =  order.getCocktails();

4. assertEquals(nbCocktails, cocktails.size());

5. }

Modifier le texte de l'étape Then et le code de la step @Then et exécuter RunCucumberTest afin de s'assurer que les tests passent toujours au VERT !

III-B - Écriture d'un nouveau scénario à l'aide du plug-in Cucumber-Eclipse

Le plug-in Cucumber-Eclipse propose via Ctrl+Espace une autocomplétion dans l'éditeur de scénarios (pour les .feature). La documentation peut être consultée ici et nous allons maintenant tester cette autocomplétion en ajoutant un nouveau scénario au fichier cocktail.feature.

Placez-vous en fin de fichier cocktail.feature sur une nouvelle ligne vide. Un appel à Ctrl+Espace propose une liste de mots clés utilisables à cet emplacement.
Choisir Scenario et compléter la ligne par l'intitulé du scénario, par exemple Scenario: Creating another new empty order.

Cette fois-ci l'exemple de ce nouveau scénario concernera Tom et Jerry.

III-B-1 - Première étape du scénario (Given)

Passer à la ligne suivante pour écrire la première étape du scénario.

- Un premier Ctrl+Espace permet de sélectionner le mot clé Given.

- Un second Ctrl+Espace affiche les steps déjà écrites dans le fichier Java. Choisir la première who wants to buy a drink et remplacer le (.*) par Tom de manière à obtenir comme première étape de ce nouveau scénario : Given Tom who wants to buy a drink.

Remarque : il se peut que la deuxième autocomplétion Ctrl+Espace ne veuille pas afficher les steps déjà écrites. Cela peut arriver si les steps du premier scénario présentent un petit symbole de warning jaune indiquant l'erreur Step '…' does not have a matching glue code. Si tel est le cas, rafraîchir le fichier cocktail.feature avec un F5 par exemple afin de faire disparaître ce symbole.

III-B-2 - Deuxième étape du scénario (When)

Passer à la ligne suivante pour écrire la deuxième étape du scénario.

De la même manière, en vous aidant de l'autocomplétion Ctrl+Espace, écrivez: When an order is declared for Jerry.

III-B-3 - Troisième étape du scénario (Then)

Passer à la ligne suivante pour écrire la troisième étape du scénario : Then there is 0 cocktails in the order.

Pour indenter correctement le fichier .feature, faire un clic droit et choisir le menu Pretty Format.

Ne pas oublier d'enregistrer ce fichier !

III-C - Exécution du nouveau scénario

Comme nous avons utilisé des steps (paramétrées) déjà implémentées dans le fichier CocktailSteps.java, il est possible de passer directement à l'exécution de ce nouveau scénario.

Exécutez le fichier RunCucumberTest. La vue JUnit vous indique maintenant que les deux scénarios passent bien au VERT !

IV - Alléger la lecture d'un scénario (And et But)

Nous allons maintenant ajouter un nouveau scénario dans cocktail.feature.
Pour envoyer un message (de mots doux ?) à la cible en même temps que la commande est demandée, écrire le scénario suivant pourrait être une solution :

1. Scenario: Sending a message with an order

2. Given Romeo who wants to buy a drink

3. When  an order is declared for Juliette

4. When  a message saying "Wanna chat?" is added

5. Then the ticket must say "From Romeo to Juliette: Wanna chat?"

En fait, pour alléger la lecture d'un scénario, le Gherkin propose deux autres mots clés, And et But , qui permettent juste de mettre de l'emphase dans le texte. Ces deux mots clés n'auront aucun effet au niveau de l'implémentation du scénario, puisqu'ils reprennent juste le mot-clé précédent.

Nous préférons donc écrire dans cocktail.feature le scénario suivant (avec le mot clé And) :

1. Scenario: Sending a message with an order

2. Given Romeo who wants to buy a drink

3. When  an order is declared for Juliette

4. And  a message saying "Wanna chat?" is added

5. Then the ticket must say "From Romeo to Juliette: Wanna chat?"

Formater (clic droit et Pretty Format) et enregistrer cocktail.feature puis exécuter RunCucumberTest.java.

Consulter la console, deux nouvelles steps sont proposées :

- une avec l'annotation @Then ;

- et l'autre avec l'annotation @When (qui correspond bien à notre étape de scénario commençant par un And précédé par When).

Récupérer dans la console le squelette d'implémentation de ces nouvelles steps et les copier/coller dans le fichier CocktailSteps.java afin de procéder à leur implémentation qui pourrait être par exemple :

1. @When("a message saying {string} is added")

2. public void a_message_saying_is_added(String something) {

3. order.withMessage(something);

4. }

6. @Then("the ticket must say {string}")

7. public void the_ticket_must_say(String somethingElse) {

8. assertEquals(somethingElse, order.getTicketMessage());

9. }

Remarque : les versions récentes de Cucumber permettent d'utiliser des Cucumber Expressions à la place des expressions régulières (regex) pour faciliter l'écriture et la lecture des steps. Ainsi, l'annotation @When peut être écrite indifféremment :

- soit à partir d'une Cucumber Expression (c'est ce que génère dorénavant la console, ici avec le parameter type par défaut {string}) : @When("a message saying {string} is added") ;

- soit à partir d'une expression régulière (regex) : @When("a message saying \"([^\"]*)\" is added").

Quant à l'annotation @Then, elle peut être écrite indifféremment :

- soit à partir d'une Cucumber Expression : @Then("the ticket must say {string}") ;

- soit à partir d'une expression régulière (regex) : @Then("the ticket must say \"([^\"]*)\"").

Pour connaître les parameter types proposés par défaut comme Cucumber Expressions, n'hésitez pas à consulter la partie Cucumber Expressions de la documentation de Cucumber qui indique également comment ajouter ses propres types ainsi que la partie Snippets de la documentation Cucumber sur la définition des steps.*

Attention aux Cucumber Expressions ! Certes elles sont plus lisibles, mais à l'heure où ce tutoriel est rédigé, l'éditeur des .feature du plug-in Cucumber-Eclipse peut dysfonctionner intempestivement et vous pouvez (sans savoir pourquoi) ne plus avoir accès au contenu de ce fichier dans votre IDE et voir s'afficher à la place l'erreur Editor could not be initialized. Tant que ce bug n'est pas fixé (ce qui ne saurait certainement pas tarder), il suffit de remplacer la Cucumber Expression par son expression régulière pour que l'éditeur refonctionne correctement… Je vous conseille quand même de continuer ce tutoriel avec des Cucumber Expressions dans la définition des steps (pour une meilleure lisibilité) et si jamais vous faites face à ce bug, passez aux expressions régulières pour retrouver le contenu de votre .feature !

Il ne reste plus qu'à procéder à l'implémentation du code métier dans la classe Order des méthodes withMessage et getTicketMessage

1. public class Order {

2. //...

3. private String message;

4. //...

5. public void withMessage(String something) {

6. this.message = something;

7. }

8. public String getTicketMessage() {

9. return "From " + from + " to " + to + ": " + message;

10. }

11. }

Relancer RunCucumberTest.java et constater que tous les scénarios passent au VERT !

Récapitulons : le mot clé And permet d'ajouter une étape supplémentaire au scénario pour alléger sa lecture. Ce mot clé ne peut se trouver qu'après un des trois mots clés de base Given, When, ou Then ou après un autre And. Il peut y avoir autant de And que le nécessite la description. Il en est de même pour le mot clé But.

V - Paramétrer un scénario

V-A - Un premier scénario paramétré…

Reprendre l'ensemble des scénarios du fichier cocktail.feature :

1. Scenario: Creating an empty order

2. Given Romeo who wants to buy a drink

3. When an order is declared for Juliette

4. Then there is 0 cocktails in the order

6. Scenario: Creating another new empty order

7. Given Tom who wants to buy a drink

8. When an order is declared for Jerry

9. Then there is 0 cocktails in the order

11. Scenario: Sending a message with an order

12. Given Romeo who wants to buy a drink

13. When an order is declared for Juliette

14. And a message saying "Wanna chat?" is added

15. Then the ticket must say "From Romeo to Juliette: Wanna chat?"

La lecture des deux premiers scénarios montre une duplication dans le descriptif des étapes. Il est possible de factoriser ces descriptions et de les regrouper au sein d'un même scénario dit paramétré, grâce au mot clé Examples pour en faciliter la lecture.

Remplacer les deux premiers scénarios par le scénario paramétré suivant et indenter correctement le fichier .feature (via un clic droit et le menu Pretty Format) :

1. Scenario Outline: Creating an empty order

2. Given <from> who wants to buy a drink

3. When an order is declared for <to>

4. Then there is <nbCocktails> cocktails in the order

6. Examples:

7. | from  | to       | nbCocktails |

8. | Romeo | Juliette |           0 |

9. | Tom   | Jerry    |           0 |

Le scénario paramétré commence par le mot clé Scenario Outline.
Il est rédigé comme un scénario classique avec, dans les étapes, des paramètres notés entre < et > : c'est une sorte de template de scénario.

Lors de l'exécution, les paramètres seront remplacés par les valeurs présentes dans les lignes de la table introduite par le mot clé Examples.
Lors de l'exécution, il y aura donc autant de scénarios exécutés que d'exemples (lignes « valuées ») présents dans la table Examples.

Exécutez RunCucumberTest.java et constatez que tous les scénarios passent au VERT !
Consultez la console qui vous indique bien que 3 Scenarios et 10 Steps ont été exécutés.
Consultez la vue JUnit pour vérifier que tous les scénarios passent au VERT ! De plus, en déroulant et ouvrant complètement toute la vue JUnit, vous verrez bien apparaître les 3 scénarios…

Un petit test pour bien s'en assurer tout de même… Changer un 0 de la colonne nbCocktails de la table Examples en 1.
Relancer les tests via RunCucumberTest.java.
Constater via la console et la vue JUnit que tous les tests ne passent plus.

Pour continuer le tutoriel, ne remettre que des 0 dans la colonne nbCocktails et exécuter RunCucumberTest.java afin de s'assurer que tous les tests passent au VERT !

V-B - Un autre scénario paramétré…

Et si on paramétrait maintenant le dernier scénario, le fichier cocktail.feature pourrait ressembler à :

1. Feature: Cocktail Ordering

3. As Romeo, I want to offer a drink to Juliette so that we can discuss together (and maybe more).

5. Scenario Outline: Creating an empty order

6. Given <from> who wants to buy a drink

7. When an order is declared for <to>

8. Then there is <nbCocktails> cocktails in the order

10. Examples:

11. | from  | to       | nbCocktails |

12. | Romeo | Juliette |           0 |

13. | Tom   | Jerry    |           0 |

15. Scenario Outline: Sending a message with an order

16. Given <from> who wants to buy a drink

17. When an order is declared for <to>

18. And a message saying "<message>" is added

19. Then the ticket must say "<expected>"

21. Examples:

22. | from  | to       | message     | expected                            |

23. | Romeo | Juliette | Wanna chat? | From Romeo to Juliette: Wanna chat? |

24. | Tom   | Jerry    | Hei!        | From Tom to Jerry: Hei!             |

Transformez votre fichier cocktail.feature de manière qu'il contienne désormais ces deux Scenario Outline, indentez-le correctement (via un clic droit et Pretty Format) et exécutez RunCucumberTest.java pour vous assurer que tous les tests passent au VERT !

Remarque : la console indique désormais 4 Scenarios et 14 Steps.

Pour en savoir plus, une documentation en ligne sur Scenario Outline est disponible dans la partie Gherkin Reference de la documentation Cucumber.

VI - Factoriser des scénarios

Pour montrer comment factoriser des scénarios, nous allons un peu modifier nos exemples précédents et considérer que dorénavant, seul Roméo (plus de Tom dans nos scénarios) offre un verre aux gentes demoiselles. Pour commencer, modifier donc votre fichier cocktail.feature de la manière suivante pour faire apparaître un Scenario et un Scenario Outline :

1. Feature: Cocktail Ordering

3. As Romeo, I want to offer a drink to Juliette so that we can discuss together (and maybe more).

5. Scenario: Creating an empty order

6. Given Romeo who wants to buy a drink

7. When an order is declared for Juliette

8. Then there is 0 cocktails in the order

10. Scenario Outline: Sending a message with an order

11. Given Romeo who wants to buy a drink

12. When an order is declared for <to>

13. And a message saying "<message>" is added

14. Then the ticket must say "<expected>"

16. Examples:

17. | to       | message     | expected                            |

18. | Juliette | Wanna chat? | From Romeo to Juliette: Wanna chat? |

19. | Jerry    | Hei!        | From Romeo to Jerry: Hei!           |

Exécuter RunCucumberTest.java et vérifier que tous les tests passent au VERT !
Remarque : la console indique désormais 3 Scenarios et 11 Steps

La lecture des scénarios montre une duplication dans les étapes Given, notamment avec l'étape : Given Romeo who wants to buy a drink.

Il est possible de factoriser une (ou plusieurs) étape(s) Given en utilisant le mot clé Background en amont de la description des scénarios de la manière suivante :

1. Feature: Cocktail Ordering

3. As Romeo, I want to offer a drink to Juliette so that we can discuss together (and maybe more).

5. Background:

6. Given Romeo who wants to buy a drink

8. Scenario: Creating an empty order

9. When an order is declared for Juliette

10. Then there is 0 cocktails in the order

12. Scenario Outline: Sending a message with an order

13. When an order is declared for <to>

14. And a message saying "<message>" is added

15. Then the ticket must say "<expected>"

17. Examples:

18. | to       | message     | expected                            |

19. | Juliette | Wanna chat? | From Romeo to Juliette: Wanna chat? |

20. | Jerry    | Hei!        | From Romeo to Jerry: Hei!           |

Modifiez votre fichier cocktail.feature pour faire apparaître la section Background.

Exécutez RunCucumberTest.java et vérifiez que tous les tests passent au VERT !
Remarque : la console indique toujours 3 Scenarios et 11 Steps

La section Background permet donc de répéter les mêmes étapes Given dans tous les scénarios.
Les étapes décrites dans le Background seront exécutées en préalable à tous les Scenario et Scenario Outline du fichier .feature.
Pour faire un parallèle avec un framework de tests unitaires en Java, on peut dire que la section Background (pour les tests fonctionnels) dans Cucumber joue en quelque sorte le même rôle que l'annotation @Before (pour les tests unitaires) dans JUnit.

Pour en savoir plus, une documentation en ligne sur Background est disponible dans la partie Gherkin Référence de la documentation Cucumber.

VII - Paramétrer le lanceur de test à partir de @CucumberOptions

Pour paramétrer le lanceur de test JUnitRunner, des options de configuration peuvent lui être transmises via l'annotation @CucumberOptions.

La liste d'options de configuration est disponible dans le manuel de référence (partie Options et List configuration options).

Une explication plus détaillée de ces options est disponible ici et là.

Dans la partie Implémenter le code de test des steps, et plus particulièrement lors de la configuration du lanceur de test pour une step dite PENDING, nous avions forcé l'option strict à true pour faire en sorte que les tests passent au ROUGE dès lors qu'une step reste à implémenter.

Nous allons maintenant nous intéresser à trois autres options :

- l'option feature pour indiquer où se trouvent les scénarios à tester ;

- l'option monochrome pour améliorer la lisibilité dans la console des résultats liés à l'exécution des scénarios ;

- l'option plug-in pour générer un rapport de tests.

VII-A - L'option feature pour indiquer où se trouvent les scénarios à tester

Peut-être, au cours de ce tutoriel, vous êtes-vous demandé pourquoi les fichiers .feature avaient été enregistrés dans le dossier src/test/resources dans un package de même nom que celui du lanceur de test ?

Lorsqu'on travaille avec un projet maven, il est d'usage d'enregistrer les fichiers .feature dans le dossier src/test/resources. En effet, les ressources de ce dossier src/test/resources sont copiées par maven dans le répertoire target/test-classes. Ainsi, si le lanceur de test se trouve dans un dossier src/test/java, son byte code (fichier .class) se retrouvera dans le répertoire target/test-classes. Donc le lanceur et les stories se retrouveront dans le même répertoire maven target/test-classes.

Par défaut, il est donc d'usage d'enregistrer les .feature dans le dossier src/test/resources dans un package identique à celui du lanceur de test.

Cependant, il est possible grâce à l'option feature d'indiquer précisément où sont enregistrées les features à tester.

L'option feature permet donc d'indiquer au lanceur de test où sont enregistrés les scénarios.
Par exemple, créez un package dojo2 dans src/test/resources et déplacez-y cocktail.feature. Exécutez RunCucumberTest : la console affiche 0 Scenario - 0 Step : le lanceur n'a pas trouvé de scénario à exécuter.

Paramétrez le lanceur de test de la manière suivante : @CucumberOptions(features="src/test/resources",strict = true) . Exécutez-le à nouveau.

La console affiche cette fois-ci 3 Scenarios - 11 Steps, le lanceur de test est allé chercher tous les .feature du dossier src/test/resources et de ses sous-dossiers.
Remarque : on aurait également pu aussi écrire features="src/test/resources/dojo2" pour plus de précision.

Avant de continuer, remettre cocktail.feature dans le package dojo et laisser comme options de configuration : @CucumberOptions(features="src/test/resources",strict = true).
Exécuter RunCucumberTest et s'assurer dans la console que 3 Scénarios ont été testés et qu'ils passent bien au VERT !

VII-B - L'option monochrome pour améliorer la lisibilité des scénarios dans la console

Exécutez RunCucumberTest.

Le résultat de l'exécution des scénarios donne dans la console un affichage similaire au suivant :

3 Scenarios (�[32m3 passed�[0m)
11 Steps (�[32m11 passed�[0m)
0m0,092s

Activer l'option monochrome permet d'améliorer la lisibilité dans la console des résultats liés à l'exécution des scénarios.
Paramétrez le lanceur de test de la manière suivante : @CucumberOptions(features="src/test/resources",strict = true, monochrome=true)
Exécutez-le à nouveau.

La console propose désormais un affichage similaire au suivant :

3 Scenarios (3 passed)
11 Steps (11 passed)
0m0,087s

VII-C - L'option plug-in pour formater et générer un rapport de tests

L'option plug-in permet de formater et générer un rapport afin de mettre en forme les résultats issus de l'exécution des scénarios selon ses préférences dans la console ou aux formats natifs html,xml ou json.

VII-C-1 - Formater avec pretty

L'option pretty est une des options de plug-in.
Activer l'option pretty permet d'afficher le Gherkin et l'éventuelle pile d'erreurs (si des scénarios sont en échec).

Paramétrer maintenant le lanceur de test avec pretty :

1. @RunWith(Cucumber.class)

2. @CucumberOptions(features = "src/test/resources", strict = true, monochrome = true, plugin = { "pretty" })

3. public class RunCucumberTest {

4. }

Exécuter RunCucumberTest et consulter la console qui propose désormais les différentes étapes Gherkin des scénarios et leurs steps java correspondantes.

VII-C-1-a - Générer un rapport au format HTML natif avec l'option html

Comme indiqué dans la rubrique Reporting de la documentation de Cucumber, l'option html est une autre option qui permet d'imprimer un rapport de test au format HTML. Un exemple est donné dans la rubrique JUnit de la partie Running Cucumber de la documentation de Cucumber indiquant que cette option est suivie du chemin qui indique où ce rapport doit être généré.

Activer l'option html de la manière suivante :

1. @RunWith(Cucumber.class)

2. @CucumberOptions(features = "src/test/resources", strict = true, monochrome = true, plugin = { "pretty", "html:target/site/cucumber" })

3. public class RunCucumberTest {

4. }

Exécuter RunCucumberTest.

Ouvrez un explorateur de fichiers. Allez dans le répertoire target du workspace de votre projet (ou plus rapidement depuis l'IDE, placez-vous dans la vue Package Explorer sur le répertoire target de votre projet, puis clic droit puis Properties puis appuyez sur le bouton Show In System Explorer présent après le chemin indiquant la Location).
Ouvrir target puis site, puis cucumber et cliquer sur index.html afin de visualiser au format HTML le rapport d'exécution des scénarios.

Remarque : après un rafraîchissement de votre projet (F5), vous pouvez aussi rechercher directement le fichier index.html depuis la vue Package Explorer de votre IDE et double-cliquer dessus : il s'ouvrira alors dans l'IDE.

Aller dans le fichier cocktail.feature. Changer la ligne Then there is 0 cocktails in the order en Then there is 1 cocktails in the order. Exécuter à nouveau RunCucumberTest et consulter/rafraîchir le fichier index.html pour découvrir votre nouveau rapport d'exécution présentant cette fois-ci un scénario en échec (ROUGE).

Avant de continuer, revenir dans la configuration initiale c.-à-d. celle où tous les tests passent : remettre Then there is 0 cocktails in the order et exécuter RunCucumberTest afin de s'assurer que tous les tests passent au VERT !

VII-C-1-b - Générer un rapport au format XML natif avec l'option junit

L'option junit permet de générer un rapport au format XML.

Modifier les options de configuration de RunCucumberTest pour activer cette option de la manière suivante :

1. @RunWith(Cucumber.class)

2. @CucumberOptions(features = "src/test/resources", strict = true, monochrome = true, plugin = {"pretty", "junit:target/cucumber.xml"})

3. public class RunCucumberTest {

4. }

Exécuter RunCucumberTest.
Depuis un explorateur de fichiers, allez dans le répertoire target du workspace de votre projet afin de consulter le fichier cucumber.xml.

VII-C-1-c - Générer un rapport au format JSON natif avec l'option json

L'option json permet de générer un rapport au format JSON.

Modifier les options de configuration de RunCucumberTest pour activer cette option de la manière suivante :

1. @RunWith(Cucumber.class)

2. @CucumberOptions(features = "src/test/resources", strict = true, monochrome = true, plugin = {"pretty", "json:target/cucumber.json"})

3. public class RunCucumberTest {

4. }

Exécuter RunCucumberTest.
Depuis un explorateur de fichiers, allez dans le répertoire target du workspace de votre projet afin de consulter le fichier cucumber.json.
Ce fichier contient toutes les informations au format JSON relatives à l'exécution des scénarios (étapes Gherkin, steps, temps d'exécution, verdict…). Ce fichier n'est pas destiné à être utilisé tel quel, mais a pour but d'être transmis traité pour permettre de proposer, par la suite, un affichage plus convivial : c'est justement ce que nous allons voir dans le paragraphe suivant avec le plug-in cucumber-reporting.

Remarques :

- il est bien sûr possible de combiner les trois options html:target/site/cucumber, json:target/cucumber.json et junit:target/cucumber.xml;

- d'autres options de configuration sont possibles : pour en savoir plus, une documentation est disponible ici par exemple.

VIII - Produire un beau rapport à l'aide du plug-in cucumber-reporting

Le plug-in cucumber-reporting permet de transformer les résultats d'exécution en JSON issus de Cucumber en document HTML5 et de les présenter sous une forme de rapports plus faciles et agréables à consulter.

La documentation du plug-in cucumber-reporting est disponible sur https://github.com/damianszczepanik/cucumber-reporting. Elle indique comment installer ce plug-in, comment le configurer et donne un aperçu du rendu des rapports qu'il est capable de générer.

VIII-A - Installer le plug-in cucumber-reporting

Pour pouvoir utiliser ce plug-in, il faut ajouter la dépendance suivante dans votre pom.xml :

1. <dependency>

2. <groupId>net.masterthought</groupId>

3. <artifactId>cucumber-reporting</artifactId>

4. <version>3.20.0</version>

5. </dependency>

Mettez à jour Maven pour que cette nouvelle dépendance soit bien prise en compte dans votre projet.

VIII-B - Configurer le plug-in cucumber-reporting

Pour utiliser le plug-in cucumber-reporting et générer les différents rapports graphiques qu'il propose, nous allons reprendre et adapter le code proposé dans la rubrique Usage sur le site de ce plug-in. Jetez un petit coup d'œil à ce code ici.

VIII-B-1 - S'assurer de générer un fichier json

Comme vous pouvez le constater, ce code se base sur un fichier json pour traiter les données issues de l'exécution des scénarios. Une des premières choses à faire est donc de paramétrer correctement les options de configuration du lanceur de test (plugin = {"json:target/cucumber.json"}) de la manière suivante :

1. @RunWith(Cucumber.class)

2. @CucumberOptions(features = "src/test/resources", strict = true, monochrome = true, plugin = {"pretty", "json:target/cucumber.json"})

3. public class RunCucumberTest {

4. }

VIII-B-1-a - S'assurer que les rapports soient générés APRÈS les tests

Pour savoir où insérer dans notre programme le code proposé, il faut se poser la question de savoir quand ce code doit être exécuté.

Ce code doit être exécuté après l'exécution de tous les scénarios. Rappelons que pour exécuter les scénarios du fichier .feature, il faut exécuter le lanceur de test (RunCucumberTest) comme un simple fichier JUnit via la commande habituelle (Run As -> JUnit Test). Idéalement, le code du plug-in devrait donc se trouver dans une méthode generateReport qui devrait être exécutée une fois que tous les tests (steps) auront été exécutés.

Au premier abord, on pourrait penser utiliser l'annotation @AfterClass de Junit 4 pour exécuter une telle méthode juste avant la fin de la classe. Mais même avec une telle annotation (j'ai testé pour vous), le rapport est généré alors que le fichier cucumber.json est encore en écriture.

Pour pouvoir générer un beau rapport et être sûr que ce rapport accède au fichier json complet et entièrement écrit, nous allons écrire une classe GenerateReport avec un main qui contiendra pour l'instant le code proposé dans la rubrique Usage du site de ce plug-in, disponible ici.

1. public class GenerateReport {

2. public static void main(String[] args) {

3. // Faire un copier/coller ici du code proposé dans la partie Usage de https://github.com/damianszczepanik/cucumber-reporting

4. }

5. }

VIII-B-1-b - Paramétrer le plug-in

Il ne reste plus qu'à paramétrer correctement le code pour l'adapter à notre application, c.-à-d. indiquer :

- le répertoire dans lequel seront stockés les rapports générés par le plug-in (target pour ce tutoriel) : new File("target") ;

- le chemin du fichier json à traiter (un seul fichier pour notre tutoriel).

Ce paramétrage s'effectue dans les premières lignes qui devraient désormais ressembler à :

File reportOutputDirectory = new File("target");
List<String> jsonFiles = new ArrayList<>();
jsonFiles.add("target/cucumber.json");

Supprimer également le bloc de code commenté par // optionally add metadata presented on main page via properties file (nous n'utilisons pas pour ce tutoriel de fichier de propriétés). Le code restant devrait être similaire au suivant :

1. import java.util.List;

2. import java.io.File;

3. import java.util.ArrayList;

5. import net.masterthought.cucumber.Configuration;

6. import net.masterthought.cucumber.ReportBuilder;

7. import net.masterthought.cucumber.Reportable;

9. public class GenerateReport {

10. public static void main(String[] args) {

11. File reportOutputDirectory = new File("target");

12. List<String> jsonFiles = new ArrayList<>();

13. jsonFiles.add("target/cucumber.json");

15. String buildNumber = "1";

16. String projectName = "cucumberProject";

17. boolean runWithJenkins = false;

19. Configuration configuration = new Configuration(reportOutputDirectory, projectName);

20. // optional configuration - check javadoc

21. configuration.setRunWithJenkins(runWithJenkins);

22. configuration.setBuildNumber(buildNumber);

24. // addidtional metadata presented on main page

25. configuration.addClassifications("Platform", "Windows");

26. configuration.addClassifications("Browser", "Firefox");

27. configuration.addClassifications("Branch", "release/1.0");

29. ReportBuilder reportBuilder = new ReportBuilder(jsonFiles, configuration);

30. Reportable result = reportBuilder.generateReports();

31. // and here validate 'result' to decide what to do

32. // if report has failed features, undefined steps etc

33. }

34. }

VIII-C - Visualiser les rapports générés par le plug-in cucumber-reporting

Exécuter RunCucumberTest pour pouvoir exécuter les scénarios. Une fois l'exécution terminée, lancer GenerateReport pour visualiser les rapports générés par le plug-in cucumber-reporting.

Ces rapports seront automatiquement générés dans le répertoire cucumber-html-reports (Ce paramètre est fixé dans la classe ReportBuilder.java du plug-in cucumber-reporting dont le code est consultable ici si vous le souhaitez).

Allez dans le répertoire target du workspace de votre projet, vous pouvez constater :

- qu'il existe bien un fichier cucumber.json ;

- qu'un répertoire cucumber-html-reports est désormais disponible dans target.

VIII-C-1 - Accéder aux rapports générés (cucumber-html-reports)

Aller dans cucumber-html-reports.
Comme indiqué dans la documentation du plug-in cucumber-reporting ici, ainsi que dans le code là, le point d'entrée pour visualiser les rapports générés par cucumber-reporting est la page overview-features.html. Vous remarquerez qu'il existe aussi les pages overview-tags.html, overview-steps.html et overview-failures.html dont nous reparlerons juste après.

VIII-C-1-a - Visualiser les différents rapports générés par cucumber-reporting

Ouvrir overview-features.html pour voir apparaître les résultats de l'exécution des scénarios sous format visuel.
Les autres pages sont accessibles à partir des onglets Tags, Steps, et Failures situés en haut à droite :

- cliquer sur Tags pour ouvrir la page overview-tags.html (utile si vous avez utilisé l'option de configuration tags, ce qui n'est pas le cas dans ce tutoriel) ;

- cliquer sur Steps pour ouvrir la page overview-steps.html ;

- cliquer sur Failures pour ouvrir la page overview-failures.html (utile si des scénarios sont en échec).

D'ailleurs, nous allons voir comment se présentent les résultats lors de l'échec d'un (ou plusieurs) scénario(s).
Aller dans le fichier cocktail.feature.
Changer la ligne Then there is 0 cocktails in the order en Then there is 1 cocktails in the order.
Exécuter à nouveau RunCucumberTest pour pouvoir exécuter les scénarios. Une fois l'exécution terminée, lancer GenerateReport pour visualiser les rapports générés par le plug-in cucumber-reporting. Consulter à nouveau le fichier overview-features.html et les onglets Tags, Steps, et Failures pour découvrir les nouveaux rapports d'exécution présentant cette fois-ci un scénario en échec (ROUGE).

Revenir dans la configuration initiale c.-à-d. celle où tous les tests passent : remettre Then there is 0 cocktails in the order et exécuter RunCucumberTest afin de s'assurer que tous les tests passent au VERT !

Remarque : en bas à gauche de la page overview-features.html se trouvent des liens en rapport avec le projet cucumber-reporting qui indiquent comment utiliser cucumber-reporting :

- sous Jenkins c.-à-d. comme plugin Jenkins (la procédure est également décrite ici) ;

- en Standalone : c'est ce que nous venons de faire ;

- en Sandwich : à utiliser si maven n'est pas disponible ;

- directement en Maven : pour configurer la génération de rapports dans le pom.xml.

IX - Remarques complémentaires

IX-A - Tout savoir sur le Gherkin…

Le Gherkin, la classe ! : pour découvrir le Gherkin, rien de tel que de le modéliser et de mettre les yeux dans le code !

IX-B - Des stories en français (Internationalisation)

Par défaut, les mots clés du Gherkin sont en anglais. Or, la réussite d'un projet BDD est fortement liée à l'écriture des stories de manière collaborative dans un langage naturel et compris de tous.

Si vous souhaitez écrire des scénarios en français, vous pouvez paramétrer le langage de votre fichier .feature en utilisant l'instruction #langage:fr en début de fichier.

Les mots clés utilisables en français peuvent être consultés dans la partie Gherkin Dialects Languages de la rubrique Gherkin de la documentation en ligne de Cucumber ou directement dans le fichier gherkin-languages.json disponible sous Github dans l'implémentation Gherkin de Cucumber. Cette documentation montre bien que Cucumber propose les mots clés Gerkhin dans de nombreuses langues : une internationalisation du Gherkin est donc possible avec Cucumber.

Des exemples de scénarios en français pour tester la version française du Gherkin peuvent être consultés ici.

IX-C - Un petit coup d'œil sur des projets utilisant Cucumber

Maintenant que vous êtes familier avec Cucumber, n'hésitez pas à aller voir comment sont écrites les features et implémentées les steps dans de vrais projets utilisant Cucumber. Pour lire les scénarios (fichiers .feature), rendez-vous dans les répertoires features.

IX-D - Écrire du bon gherkin : attention aux antipatterns !

Un récent podcast entre Aslak Hellesøy, Matt Wynne, et Steve Tooke s'est intéressé aux antipatterns autour des outils BDD de type Cucumber, car contrairement aux idées reçues ce n'est pas si facile d'écrire du bon Gherkin.

- Ce podcast est disponible sur : https://cucumber.io/blog/2016/05/09/cucumber-antipatterns
Son contenu a été repris dans les articles suivants :

- http://www.thinkcode.se/blog/2016/06/22/cucumber-antipatterns ;

- https://cucumber.io/blog/2016/07/01/cucumber-antipatterns-part-one ;

- https://cucumber.io/blog/2016/08/31/cucumber-antipatterns-part-two.

X - Références

- Le site de référence est : cucumber.io avec :

- Documentation de Cucumber (accueil) ;

- Documentation de Cucumber par menus.

- Une liste de projets utilisant Cucumber.

- La documentation du plug-in Cucumber-Eclipse est disponible sur https://github.com/cucumber/cucumber-eclipse.

- Zoom sur les options de configuration du lanceur de test : JUnit Runner with @CucumberOptions.

- Liens utilisés pour réaliser ce tutoriel :

- https://github.com/CodingDojoPolytech/cucumber-mockito-shakespeare ;

- http://www.arolla.fr/blog/2016/02/un-tutorial-cucumber-pour-java/ ;

- https://damienfremont.com/2016/05/09/how-to-cucumber-test-report-plugin-2-with-maven-and-java ;

- https://damienfremont.com/2015/01/29/tests-bdd-avec-cucumber-java/ ;

- http://toolsqa.com/cucumber/cucumber-tutorial/.

- Cucumber (software) sur Wikipedia.

- Autres frameworks BDD :

- Un tutoriel de prise en main JBehave (le premier framework BDD développé en Java par Dan North) est disponible ici en version rapide ou plus détaillée (écrit à l'occasion des JDEV2013).

XI - Remerciements

Cet article a été publié avec l'aimable autorisation de Isabelle Blasquez.

Nous tenons à remercier naute pour sa relecture orthographique attentive de cet article, Winjerome et Mickael Baron pour la mise au gabarit.