mercredi 22 février 2012

Greenpepper 2.9 - Tutorial d'installation et d'utilisation

Greenpepper, commercialisé par la société Pyxis Technologies Inc., est un outil de spécifications et de tests fonctionnels automatisés. Dans le cas où les développement sont dirigés par les tests, il s'agit de l'ATDD.

Greenpepper permet donc l'écriture de cas de tests en langage simple par la MOA et leur exécution. Ces scénarios peuvent également être accompagnés de spécifications puisque l'outil est installé sur un wiki. Il peut même être intégré à Jira et Eclipse.

Je vais tenter dans ce tutorial d'introduire l'ATDD en parlant de cet outil assez puissant qui est Greenpepper. Je commencerai par son installation pour parler ensuite de son utilisation par la MOA et terminer par les différents types de tests que l'on peut écrire et exécuter, ainsi que leur implémentation.


1. Installation de Greenpepper
2. Rédaction des pages de spécification par la MOA
3. Implémentation des fixtures par la MOE
4. Greenpepper avancé 


1. Installation de Greenpepper


Dans ce tutoriel, je vais utiliser Confluence comme base de travail pour utiliser Greenpepper. En effet, il est possible de l'installer sur ce wiki et disposer de pages de spécifications exécutables.
Confluence est un wiki d'entreprise et il offre une architecture puissante de gestion de plugins ce qui nous permettra d'y installer le plugin Greenpepper.
Ce dernier est disponible également sous forme de plugin à installer sur XWiki.

L'image suivante présente les différents systèmes sur lesquels Greenpepper peut être installé. Nous allons nous intéresser dans ce tutoriel à Confluence, Maven et Eclipse. Je vous laisse regarder le site pour son utilisation avec les autres systèmes.





1.1 Téléchargement


Tout d'abord, le plugin Greenpepper pour Confluence est à télécharger à l'adresse suivante : http://greenpeppersoftware.com/confluence/display/GPW/Download+Archive

La version que je présente ici est la version 2.9 qui est compatible avec la version 3.5.13 du Wiki d'entreprise Confluence.
A l'heure où j'écris ces lignes, Pyxis tech a sorti une version beta stable compatible avec la nouvelle version de Confluence 4. Mais nous l'utiliserons pas dans ce tutoriel.
Je ne détaillerais pas non plus l'installation de Confluence. La documentation est assez détaillée sur le site dédié à l'adresse suivante : http://confluence.atlassian.com/display/DOC/Confluence+Documentation+Home.
Sur ce tutoriel, il s'agit de la version 4. Mais la procédure d'installation est exactement la même que pour la version 3.5.


1.2 Installation


Comme indiqué sur la documentation de Greenpepper, il faut installer le fichier
greenpepper-confluence-plugin-2.9-complete.jar

en le copiant directement dans le répertoire :
.../atlassian/confluence-3.5.13-std/confluence/WEB-INF/lib



1.3 Création de l'espace "Tutorial Greenpepper"


 Pour utiliser Greenpepper, il est nécessaire de créer un espace sur Confluence et de lui appliquer le thème Greenpepper. J'ai appelé l'espace utilisé pour ce tutoriel "Tutorial Greenpepper".

La procédure de création d'un espace sur Confluence est bien détaillée sur le site de Greenpepper. Je ne le ferais donc pas ici. 


1.4 Configuration


Une fois le plugin copié dans le répertoire de Confluence, il faut aller sur l'espace d'administration de ce dernier et se loguer. Pour y accéder, après s'être identifié sur Confluence, cliquez sur le menu en haut à droit pour ouvrir l'espace d'administration.



Entrez votre nom d'utilisateur et votre mot de passe et normalement, vous devez atterrir sur la console d'administration. A ce stade, nous devons cliquez sur "plugins" sur le menu de gauche pour voir apparaître la liste des plugins installés sur Confluence. Dépliez le plugin GreenPepper Toolbox, vous y êtes.



Maintenant, nous allons configurer le plugin en cliquant sur "Configure".

1.4.1 Configuration de la base de données


Tout d'abord, il faut créer une base de données sur notre SGBD favori que nous appellerons "greenpepperDB". Une fois la base de données créée, il faut dire à Greenpepper où enregistrer ses données.
Par défaut, la base de données sélectionnée est "HSQL". Cette base est utile lors de l'évaluation de GreenPepper et non sa mise en production. Nous allons donc choisir dans la liste déroulante "Custom Install" et sélectionner PostgreSQL. C'est la base que j'ai choisi mais vous pouvez bien entendu sélectionner une base différente.



Vous remarquerez qu'il faut saisir une ressource JNDI. celle-ci est à créer dans le fichier server.xml du serveur tomcat de Confluence.
.../atlassian/confluence-3.5.13-std/conf/server.xml

Voici le fichier :



Après avoir enregistré le fichier server.xml et renseigné la ressource JNDI dans l'espace de configuration de la base de données, sauvegardez cette configuration en cliquant sur "save", fermez Confluence (ce n'est pas obligatoire) et redémarrez le pour que le serveur puisse prendre en compte la nouvelle ressource que nous venons d'ajouter.

Si votre serveur est redémarré, allez sur l'espace d'aministration de Confluence et retournez sur la page de configuration de Greenpepper.



1.4.2 Saisie de la licence


Nous allons maintenant saisir notre numéro de licence après l'avoir payé bien entendu. Je vous laisse le plaisir d'aller découvrir les prix de Greenpepper à l'adresse suivante : Acheter Greenpepper
Saisissez votre numéro de licence et cliquez sur "upload". Si le numéro est valide, tout va bien et cet écran devrait s'afficher.





1.4.3 Configuration du Runner Maven


Le runner est le moteur d'exécution des fixtures (lien entre les pages de tests et leur implémentation). Nous allons nous intéresser au "Maven Runner" qui nous permettra de lier le pom.xml de notre projet aux pages de spécifications de Greenpepper. Il nous permettra également d'exécuter les pages de spécifications directement sur Confluence.

Il est préférable d'utiliser le "Maven Runner" parce que la Configuration du moteur d'exécution de vos tests peut être fastidieuse si vous avez un nombre important de dépendances. Le Runner Maven vous permet d'utiliser votre pom.xml existant pour résoudre les dépendances nécessaires à l'exécution de vos tests fonctionnels. Seul l'élément "dependencies" du pom.xml est lu. Les artefacts trouvés seront résolus et ajouté au classpath du moteur. L'artefact du projet lui-même fera également partie du classpath.

Configurons donc le Runner. Pour cela, il faut cliquer sur l'onglet "Runner" et choisir "Add new runner".
Remplissez le formulaire qui s'affiche comme suit :
  • Name : Maven Runner
  • Command line :  java -cp ${classpaths} ${mainClass} ${inputPath} ${outputPath} -l ${locale} -r ${repository} -f ${fixtureFactory} --xml --pdd ${projectDependencyDescriptor}
  • Main class : com.greenpepper.maven.runner.Main
  • Environment : JAVA
"Secured Mode" est prévu pour le "Remote Agent" que nous n'allons pas utiliser ici.
Dans la partie "classpaths", il faut indiquer le chemin des librairies de Maven et le celui du plugin greenpepper pour maven.

  • .../apache-maven-2.0.9/boot/classworlds-1.1.jar 
  • .../apache-maven-2.0.9/lib/maven-2.0.9-uber.jar 
  • .../atlassian/confluence-3.5.13-std/confluence/WEB-INF/lib/greenpepper-maven-runner-2.6-complete.jar 
Vous remarquerez que j'ai utilisé la version 2.0.9 de maven. Ceci est dû aux différences entre les librairies de la dernière version de maven et celle que j'ai utilisée.
En exécutant les spécifications avec la dernière version, greenpepper ne trouvait pas quelques librairies nécessaires à l'exécution des fixtures.


A l'issue de cette étape, vous devez normalement avoir l'écran suivant :





1.4.4 Configuration du projet Greenpepper

 

Passons à l'onglet suivant "Project Management". Nous allons dans cette partie configurer l'espace "Tutorial Greenpepper" que nous avons créé au départ. 
 
Pour cela, dans la fenêtre qui s'affiche, cliquez sur la liste déroulante "spaces", puis sélectionnez "Tutorial Greenpepper". 
 
Cliquez ensuite sur "edit" pour éditer les informations affichées.  
 

Dans "GreenPepper Project Name", sélectionnez "new project" pour créer un nouveau projet et saisissez un nom pour ce projet. 

Saisissez un alias pour le projet dans "GreenPepper Alias". J'ai choisi ici l'alias "TGrP".

Saisissez ensuite un nom d'utilisateur et un mot de passe.


Pour définir le "System Under Test" (système testé) cliquez sur "Add a new System under test". Dans le formulaire affiché, saisissez le nom de votre SUT, sélectionner Maven_Runner (le nom que vous avez choisi en définissant le "Maven Runner") et dans "Project dependency descriptor" saisissez le chemin vers le pom.xml parent de votre projet. J'entends par pom parent, le pom au niveau le plus élevé de vos projets dans eclipse. 

Si vous avez, par exemple, un projet eclipse pour chaque couche (DAO, métier...), vous devez avoir un pom pour chaque projet. Dans ce cas, vous devez également avoir un pom parent de ces projets. C'est celui-ci qu'il faut renseigner dans
"Project dependency descriptor". Pour les besoins du tutorial, je n'ai utilisé qu'un projet eclipse. 


Enfin, mettez le chemin complet vers le jar généré (en faisant un "mvn clean install") de votre projet greenpepper dans "Fixtures Classpaths".


Une fois tout ceci fait, vous devriez avoir l'écran suivant : 




1.4.5 Installation et configuration du plugin Eclipse


Le plugin Eclipse est à télécharger sur le site de Greenpepper. Concernant l'installation, je vous laisse aller voir l'url suivante qui détaille bien les différentes étapes : http://greenpeppersoftware.com/confluence/display/GPWODOC/1.+Install+GreenPepper+Eclipse+plugin

Une fois le plugin installé, il faut rendre le projet sur Eclipse "Greenpepperized". Pour cela, sélectionner votre projet, cliquer sur Greenpepper sur le menu d'Eclipse et activer "Project Greenpepperized".
 

Ouvrez la vue "Repository View" (celle de "Greenpepper". Oui, elle ne s'appelle pas Greenpepper...). Cliquer droit sur votre projet qui vient d'apparaître sur cette vue. 
 
Cliquez sur Greenpepper sur le menu de gauche pour voir apparaître les paramètres Greenpepper du Projet. 
 
Dans la liste déroulante "project name", sélectionner le nom de l'espace Greenpepper que vous avez créé sur Confluence. 
 
Sélectionner ensuite le nom du "System Under Test" en renseignant par la suite votre login et mot de passe dans le tableau en dessous. Renseignez également "Runner Directory" en mettant le chemin vers le plugin greenpepper présent dans le répertoire lib de Confluence (/home/salim/atlassian/confluence-3.5.13-std/confluence/WEB-INF/lib).
 
Sur le menu de gauche, cliquez sur "Advanced Settings". Si vous utiliser Spring, par exemple, dans "class name", vous devez saisir le nom de la classe surchargeant la classe DefaultSystemUnderDevelopment. Nous verrons dans la section "Greenpepper Avancé" à la fin de ce tutorial en quoi consiste cette surcharge. 
 
Dans "constructor args", vous pouvez éventuellement mettre le chemin relatif vers votre context spring (xml).

A ce stade, la configuration du plugin Eclipse doit être OK.



2. Rédaction des pages de spécification par la MOA


Les méthodologies de gestion projet classiques impliquent une gestion linéaire de toutes les activités d'un projet. Les premières phases de description du besoin sont gourmandes en temps et produisent des documents qui sont souvent peu lus ou simplement ignorés par les participants. De plus, les besoins sont spécifiés pour une version entière et non pour une fonctionnalité.

Ces documents sont souvent :
  • Les spécifications fonctionnelles générales
  • Les spécifications fonctionnelles détaillées
  • Les spécifications techniques générales
  • Les spécifications techniques détaillées
  • etc.

Dans les méthodologies agiles, nous parlons de "User stories". Une "user story" doit définir le rôle, l'action et l'objectif à atteindre d'une fonctionnalité du logiciel. De plus, sa granularité doit être fine. Plus elle le sera, plus elle sera simple à exprimer, à développer et à tester. Je vous propose la lecture de cet article sur le principe de "User Story".  

Une fois les "user stories" définies, la question qui nous vient à l'esprit est  comment  passer du besoin exprimé en langage métier ("User Story") au produit développé avec un langage de programmation ? 

L'approche ATTD (Acceptance Test Driven Development) répond à cette question en permettant d'exprimer un besoin métier par des critères de vérification et contrôler la concordance entre ce besoin et ce qui est réalisé (Je vous envoie à ces articles sur l'ATTD et le BDD).
C'est ce qui va nous amener à parler de Greenpepper.

Cet outil va permettre à la MOA de rédiger les "user stories" du projet en langage métier sous forme de tests exécutables.
C'est là que ça devient intéressant !
Puisque ce sont des spécifications exécutables, le besoin exprimé sous forme de test sera implémenté par la MOE. Il représente donc l'état de l'application à un moment donné et permet de mesurer réellement la réponse au besoin.
Cette documentation du logiciel n'est donc jamais obsolète car elle est "branchée" à l'application.

Tout d'abord, Greenpepper peut être installé sur un Wiki d'entreprise. La MOA peut donc créer un espace de spécifications et y mettre toutes les user stories classées par domaine.

Prenons un exemple...

Pour le service RH d'une entreprise, la MOA veut créer un logiciel de gestion des salaires et de la formation des salariés. Nous allons donc créer une "page d'accueil" sur notre espace Greenpepper sur Confluence qui s'appellera "Gestion des ressources humaines" qui contiendra ces fonctionnalités. Cette page peut contenir la description du projet mais sans trop détailler le besoin ni les fonctionnalités.

Après avoir rédigé cette page d'accueil, nous devons créer autant de pages que de fonctionnalités classées par domaine.

Imaginons qu'on ai les domaines "Salaires" et "Formation". Chaque page correspondant à un domaine comportera la description de celui-ci. Il n'est pas nécessaire de mettre cette description dans la page d'accueil.

Une fois les pages de domaines créées, créons les pages de fonctionnalités de chaque domaine.

Domaine "Salaires" : 
  • Calcul des Salaires
  • Gestion des augmentations
  • ...
Domaine "Formation" :
  • Inscrire un salarié à une formation
  • ...

 

2.1 Structure des pages Greenpepper sur Confluence


Après avoir créé une page sur Confluence dans un espace ayant pour thème Greenpepper, il est possible de l'éditer.  Il existe deux modes d'édition d'une page :
  • Rich text :
Ce mode est le mode classique mettant à disposition de l'utilisateur un éditeur de texte assez simpliste mais qui permet néanmoins d'ajouter tous types d'éléments (texte, liens, images...).



  • Wiki mode : 
C'est un mode d'édition avancé permettant l'écriture des pages avec un langage spécifique. Il est préférable de créer les pages en mode "Rich Text" et de les éditer en mode "Wiki" si elles contiennent des erreurs après leur enregistrement.

Voici la même page que nous avons crée ci-dessus en mode Wiki :



Attention ! En enregistrant la page, il est possible que le mode "Rich text" rajoute des caractères au texte que vous avez saisi.

Exemple :

Pour créer un tableau en mode "Rich Text", il faut cliquer sur "Insert table" et saisir les valeurs, couleurs... voulues.
Par contre en mode "Wiki", le tableau se présente sous cette forme :


|| colonne1  || colonne2 || colonne3 ||
| valeur | valeur | valeur |
| valeur | valeur | valeur |
| valeur | valeur | valeur |


Après avoir enregistré la page en mode "Rich Text", si nous l'ouvrons en mode "Wiki", il est possible de constater que les caractères "\" ont étés ajouté dans chaque cellule du tableau, ce qui peut fausser les valeurs attendues par le test.


Exemple :


||\colonne1\ ||\colonne2\||\colonne3\||
|\valeur\|\valeur\|\valeur\|
|\valeur\|\valeur\|\valeur\|
|\valeur\|\valeur\|\valeur\|


Il suffit alors d'éditer la page en mode "Wiki" et de supprimer ces caractères. 


2.2 Description générale du projet


Pour introduire le projet, nous allons créer la page d'accueil du projet directement dans l'espace "Tutorial Greenpepper" (cf. 2.1 Structure des pages Greenpepper sur Confluence) et ajouter un paragraphe de description. Il est également possible d'ajouter à cette page toute sorte de graphes, modèles, description de la société etc. 



2.3 Domaines fonctionnels du projet


Depuis la page d'accueil, créons une page pour chaque domaine fonctionnel du projet.

  • Domaine "Salaires"
  • Domaine "Gestion des compétences"
Comme pour la page d'accueil, il est possible d'y ajouter tout élément permettant la description du domaine. Cette description fait office de spécifications.


2.4 Fonctionnalités métier


Une page doit être créée pour chaque fonctionnalité du domaine. Ce sera bien entendu, une page fille du domaine concerné, contenant elle-même des spécifications (paragraphes décrivant la fonctionnalité + captures d'écran éventuellement...). 


2.5 Scénarios


Chaque fonctionnalité peut avoir plusieurs scénarios. Et bien, vous l'aurez deviné, depuis la page de la fonctionnalité, il faut créer une sous page pour chaque scénario et ajouter éventuellement les spécifications correspondantes.
A ce stade, nous obtenons une arborescence que l'on peut visualiser en cliquant sur Browse>Pages sur le menu en haut à droite.
Après avoir cliqué sur Pages, il est possible de choisir le type d'affichage des pages selon trois modes :
Recently Updated | Alphabetical | Tree

Si l'on choisi le mode Tree, nous obtenons l'arborescence des spécifications du projet.




2.6 Écriture des tests


Pour chaque test, il existe trois étapes :

  • Phase d'initialisation : Cette étape permet l'initialisation du contexte  du test fonctionnel. Elle permet l'initialisation des données utilises à notre test. Par exemple, pour ajouter un salarié à une formation, il faut que le salarié et la formation existent.
  • Phase d'action : Phase permettant d'exécuter l'action testée
  • Phase de vérification des résultats retournés par la phase précédente (résultats du test)

Passons à l'écriture des tests. Nous allons en écrire un pour le scénario "Scénario 1".
Imaginons que ce soit le scénario classique d'ajout d'un salarié à une formation existante.


2.6.1 Phase d'initialisation


Nous n'allons pas initialiser le contexte directement sur la page du scénario mais créer au même niveau que les pages de domaines fonctionnels, une rubrique "setup" dans laquelle nous mettrons toutes les pages d'initialisation et que nous inclurons dans les tests qui en ont besoin à l'aide de l'outil "insert macro" de l'éditeur de texte.
La page d'initialisation n'est pas écrite directement sur la page du scénario car nous pouvons en avoir besoin dans une autre page. Pour cela, une fois créée sur une page indépendante, il est possible de l'inclure tout simplement, à chaque fois que nous en avons besoin.  


Ouvrez la page du projet "Gestion des ressources humaines" et créez une page "setup" dans laquelle il faut créer deux sous-pages "setup Salariés" et "setup Formations".


Page d'initialisation des salariés "setup Salariés" :




Page d'initialisation des salariés "setup Formations" :




Les entêtes des deux premières colonnes contiennent le type ("setup" en minuscule) et le nom de la fixture* d'initialisation ("SetupSalaries" et "SetupFormations" en CamelCase sans accents).
Le nom des colonnes ne doit pas contenir d'accents ni d'espaces. 

* Une fixture représente la structure de notre test. En créant une fixture vous définissez comment la table est composée (quels champs font partie de la table) et quels enregistrements seront remplis dans la table de test.

A ce stade notre arborescence se présente comme suit :





Une fois le tableau d'initialisation terminé, ajoutez une autre page d'initialisation des formations et retournez sur la page d'édition de notre scénario.


2.6.2 Types de tests


Pour le besoin du tutorial, j'ai crée autant de sous page de la page "Scénario 1" que de types de tests.


2.6.2.1 DoWith


Ce type de test permet l'exécution d'une action.
Outre le type du test et le nom de la fixture, il faut ajouter un mot clé au début de chaque test : 

Accept Confirme que l'action a bien été exécutée par le système testé.

Check Vérifie si la valeur attendue est bien égale à celle retournée par le système testé.
Reject L'action doit être rejetée par le système testé.
Display Affiche une valeur retournée par le système testé.









Si nous avons la liste des employés et celle des formations que nous voulons enregistrer Marie Dupont à la formation Greenpepper nous allons écrire cette fixture :







Là, je vous dois une explication...

Tout d'abord, il faut inclure les setup que nous avons créé précédemment à l'aide de l'outil d'insertion de macro ou en mode wiki à l'aide de la commande : {greenpepper-include:pageTitle=setup Salariés}. Cette commande permet d'inclure une page créée précédemment.
Pour ce type de test, les entêtes ne changent pas par rapport aux tableaux d'initialisation (type de test, nom de la fixture). 

Vous avez dû remarqué qu'il n'y a pas de colonne. Par contre, j'ai ajouté une ligne représentant l'action à exécuter par le système testé. 
Il faut pour le DoWith, mettre en premier le mot-clé qui va définir quel type de test nous écrivons, et alternativement une partie de la phrase qui définit le contexte de l'action réalisée (le comment) et un paramètre (le quoi ou le qui).

| Mot clé | comment | quoi ou qui | comment | quoi ou qui | ... |

Remarque importante : Ce type de test ne teste pas le résultat retourné par l'action réalisée par le système testé mais définit cette action. Autrement dit, je dis simplement au système de réaliser une action particulière (exemple : inscrire Marie Dupont à la formation Greenpepper). 


Remarque : Nous ne pouvons pas encore exécuter le test puisqu'il n'a pas encore été implémenté par la MOE. Une fois implémenté, il est possible de l'exécuter directement sur Confluence.

Le résultat de l'exécution se présente comme suit :





Après exécution du test, Greenpepper surligne les cellules contenant le résultat attendu et affiche un compte rendu en haut à droite de la page contenant le nombre de tests OK, le nombre de tests qui ont échoués et celui en erreur.


 2.6.2.1 Set of et List of


Ces types de test permettent d'écrire un tableau dans lequel nous pouvons mettre les valeurs attendues.

Set of : liste non triée
List of : liste triée



Par exemple, si l'action du test est l'inscription de la salariée Marie Dupont à la formation Greenpepper, nous pouvons utiliser le type de test DoWith pour réaliser l'inscription et vérifier cette inscription à l'aide d'un tableau Set of ou List of. Ce type de tableau retourne tous les enregistrements présents dans la base de données et non une partie des salariés inscrits à des formations par exemple.

Dans ce type de tableau, nous allons donc retrouver la liste des salariés avec le libellé des formations auxquelles il sont inscrits.  

Nous pouvons écrire le test de la manière suivante :




Ce test signifie que l'on s'attend à retrouver Marie Dupont inscrite à la formation Greenpepper et Pierre Dupont à la formation agile.

Une fois le test implémenté, voici comment il se présente après exécution :




2.6.2.2 Rule for


Ce type de test permet d'exprimer le test sous forme de question.
Est-ce que Marie Dupont est inscrite à la formation Greenpepper ?
Les premières colonnes représentent les paramètres d'exécution du test.
La ou les colonnes portant un "?", représentent le résultat attendu.




2.6.2.2 Scenario


Le type de test scénario permet de "libérer" le rédacteur du test des contraintes des autres types de test.
Il permet l'écriture du test en langage naturel mais sans accents.



Une fois que les spécifications exécutables sont rédigées, l'équipe technique peut commencer à développer les fonctionnalités demandées et les fixtures (tests) correspondantes. 

Il est important que les tests fonctionnels soient rédigés avant le début développement des fonctionnalités (cf. BDD, ATTD). 

Une fois que le développement est terminé, il est possible d'exécuter ces tests directement sur la page que vous avez rédigé en cliquant sur le bouton "Execute". Il n'apparaît pas sur les captures d'écran ci-dessus car il faut cocher "Greenpepperized" pour rendre le test exécutable.



3. Implémentation des fixtures par la MOE


Nous allons maintenant implémenter les fixtures rédigées par la MOA (cf. ci-haut).

Tout d'abord, je considère que l'application est déjà initialisée (couche d'accès aux données, couche métier...).

Pour qu'une page de spécifications soit exécutable, il faut cocher "GreenPepperized" sur cette page sur Confluence. Elle apparaîtra ensuite comme une spécification exécutable sur Eclipse. 

/!\ Remarque importante /!\ : Il est à noter que lors de l'implémentation des fixtures, la couche testée est la couche métier. Pour toutes les actions, tests effectués, ce sont les "services" de la couche métier qui sont appelés, excepté pour les setup des fixtures où il est possible d'appeler les DAO pour initialiser les données.
Par ailleurs, Greenpepper ne teste pas la couche de présentation. Il existe d'autres outils pour cela tel que Selenium.



3.1 Implémentation des setup


Le plugin Greenpepper d'Eclipse permet la génération des fixtures avec le code par défaut pour leur implémentation.
Pour cela, ouvrez la vue "Repository view". Sur l'arborescence des fixtures, allez à la section setup et cliquer droit que le setup "Setup Formations".
Activer tout d'abord "Switch to Working Copy". Ceci a pour effet le téléchargement systématique depuis Confluence de la fixture avant son exécution. Ensuite, cliquer sur "Create fixture".
Sur la fenêtre qui apparaît, choisissez le package dans lequel vous voulez créer votre fixture.


Une fois cette boite de dialogue validée, vous devez avoir créé la classe SetupFormationsFixture.

Implémentons cette classe :

Remarque : Il est bien entendu possible d'utiliser Spring3 ou EJB3, mais j'ai volontairement simplifié le code car ces frameworks ne font pas l'objet de ce tutorial.
Vous trouverez quelques éléments concernant l'utilisation de Spring3 dans la dernière parie : "4. Greenpepper avancé". 


Dans la classe SetupFormationsFixture, une fois générée par le plugin, vous pouvez aisément modifier les types des propriétés et remplacer le type de retour de la fonction enterRow par void.



SetupFormationsFixture :

package com.tutorial.greenpepper.gp.setup;

public class SetupFormationsFixture {

    public Date  date;
    public String description;
    public String libelle;
    public String lieu;

    private GPEntityManager gpEntityManager = new GPEntityManager();

    public SetupFormationsFixture() {
    }

    public void enterRow() {
        gpEntityManager.createFormation(date, description, libelle, lieu);
    }

}


GPEntityManager :


package com.tutorial.greenpepper.gp.setup;

import com.tutorial.greenpepper.dao.FormationDao;
import com.tutorial.greenpepper.domain.Formation;

public class GPEntityManager {

    private FormationDao formationDao = new FormationDao();

    public Formation createFormation(String date, String description, String libelle, String lieu) {

        return formationDao.createFormation(date, description, libelle, lieu);

    }

}

FormationDao :

package com.tutorial.greenpepper.dao;

import java.util.Calendar;

import com.tutorial.greenpepper.domain.Formation;

public class FormationDao {

    public Formation createFormation(Calendar date, String description, String libelle, String lieu) {
        Formation formation = new Formation();
        formation.setDate(date);
        formation.setLibelle(description);
        formation.setLieu(lieu);
        formation.setDescription(description);
        return formation;
    }

}


 Avant de pouvoir exécuter cette fixture, il faut éditer la page de test sur Confluence et ajouter le package de la classe :

{greenpepper-import:com.tutorial.greenpepper.gp.setup}

Il faut également faire un "mvn install" pour builder votre projet.
En effet, lors de l'exécution d'une fixture sur Confluence, Greenpepper charge le jar que vous lui avez indiqué dans le "fixture Classpaths".

Mettez à jour la page sur la vue "Repository View" sur Eclipse et exécutez la page. Si vous n'avez pas d'erreurs, le test a réussi. 
Notez qu'en exécutant les setup, vous n'avez aucun résultats, contrairement aux autres tests. Les setup ne sont pas considérés comme des tests.

Je vous laisse implémenter le setup des salariés.


3.2 Implémentation des fixtures


3.2.1 Scénario 1 - DoWith


Comme pour les setup, il faut générer la fixture à partir d'Eclipse.

Le code généré est le suivant :


InscrireSalarieFormationFixture :

package com.tutorial.greenpepper.gp;

public class InscrireSalarieFormationFixture {
  
    public InscrireSalarieFormationFixture() {
        // TODO Auto-generated Constructor stub
    }

    public String enregistrerLaSalarieeALaFormationTrue(String param1, String param2) {
        return null;
    }

}

Nous allons remplacer ce code par le code suivant :

InscrireSalarieFormationFixture :

package com.tutorial.greenpepper.gp;

import com.tutorial.greenpepper.gp.setup.GPEntityManager;

public class InscrireSalarieFormationFixture {
  
    private GPEntityManager gpEntityManager = new GPEntityManager();

    public InscrireSalarieFormationFixture() {

    }

  public boolean enregistrerLaSalarieeALaFormationTrue(String prenomNom, String libelleFormation) {
        return gpEntityManager.enregistrerLaSalarieeALaFormation(prenomNom, libelleFormation);
    }

}


La fonction enregistrerLaSalarieeALaFormationTrue de gpEntityManager fait appel au service métier correspondant pour enregistrer le salarié à la formation passés en paramètres et retourne un booléan qui fera passer notre test au vert si elle retourne true. 


3.2.2 Scénario 1 - List of et Set of

Sur cette page, nous avons deux fixtures : ListeDesInscriptionsFixture et ListeNonOrdonneeDesInscriptionsFixture.

Elle s'implémentent de la même manière sauf que la fixture du SetOf renvoie un Set et celle du ListOf renvoie une List.


Code généré :

ListeDesInscriptionsFixture :

package com.tutorial.greenpepper.gp;

import java.util.Set;

import com.tutorial.greenpepper.domain.InscriptionVO;
import com.tutorial.greenpepper.gp.setup.GPEntityManager;

public class ListeDesInscriptionsFixture {

    private GPEntityManager gpEntityManager = new GPEntityManager();

    public Set<InscriptionVO> query() {
        return gpEntityManager.getInscriptionsNonOrdonnees();
    }
}

Code modifié :

GPEntityManager :

[...]

public Set<InscriptionVO> getInscriptionsNonOrdonnees() {
        Set<InscriptionVO> result = new HashSet<InscriptionVO>();
        List<Salarie> salaries = salarieService.getSalaries();
        for (Salarie salarie : salaries) {
            for (Formation formation : salarie.getFormations()) {
                InscriptionVO inscription = new InscriptionVO();
                inscription.setFormation(formation.getLibelle());
                inscription.setNom(salarie.getNom());
                inscription.setPrenom(salarie.getPrenom());
                result.add(inscription);
            }
        }
        return result;
}

[...]



3.2.3 Scénario 1 - Rule For


Code généré automatiquement :

VerificationInscriptionFixture :
package com.tutorial.greenpepper.gp;


public class VerificationInscriptionFixture {

    public String nom;
    public String prenom;

    public VerificationInscriptionFixture() {
        // TODO Auto-generated Constructor stub
    }

    public String formation() {
        // TODO Auto-generated Method stub
        return null;
    }

}

Code modifié :

VerificationInscriptionFixture :

package com.tutorial.greenpepper.gp;

import com.tutorial.greenpepper.gp.setup.GPEntityManager;

public class VerificationInscriptionFixture {

    public String nom;
    public String prenom;
    private GPEntityManager gpEntityManager = new GPEntityManager();

    public VerificationInscriptionFixture() {
    }

    public String formation() {
        return gpEntityManager.verifierInscriptionSalarie(nom, prenom);
    }

}


GPEntityManager :

[...]
public String verifierInscriptionSalarie(String nom, String prenom) {
        return salarieService.getLibelleFormationBySalarie(nom, prenom);

[...]



3.2.4 Scénario 1 - scenario


Code généré automatiquement :

ScenarioTestFixture :
package com.tutorial.greenpepper.gp;


public class ScenarioTestFixture {

    public ScenarioTestFixture() {
        // TODO Auto-generated Constructor stub
    }

}

Code modifié :

ScenarioTestFixture :
package com.tutorial.greenpepper.gp;


public class ScenarioTestFixture {

     private GPEntityManager gpEntityManager = new GPEntityManager();

    public ScenarioTestFixture() {
        // TODO Auto-generated Constructor stub
    }

    @Given("inscrire (\\w+) (\\w+) a la (\\w+) (\\w+)")
    public void inscrire(String prenom, String nom, String libelleFormation, String intitule) {
        gpEntityManager.inscrireSalarieAUneFormation(prenom, nom, libelleFormation.concat(" ").concat(intitule));
    }

    @Check("verifier que (\\w+) (\\w+) est bien inscrite a la (\\w+) (\\w+)")
    public boolean verifierque(String prenom, String nom, String libelleFormation, String intitule) {
        return gpEntityManager.salarieInscritALaFormation(prenom, nom, libelleFormation.concat(" ").concat(intitule));
    }

}

La première fonction représente un type de test "given". C'est à dire que c'est une instruction visant à initialiser le contexte. C'est exactement le même type d'instruction que le test "Do With".
Pour l'implémenter, il faut :
- Identifier les mots pouvant être des paramètres et les remplacer par une expression régulière.
- Ajouter le type de test en tant qu'annotation de la méthode, ici @Given. Cette annotation est présentation dans la libraire Greenpepper importée comme dépendance dans le pom.xml du projet.
- Chaque expression régulière est passée en paramètre de la fonction qui retourne un booléen.

La deuxième fonction comporte l'annotation @Check. Ce test peut être comparé au type de test "Rule For" qui vérifie l'existence d'un enregistrement en fonction de quelques paramètres qui sont formalisés ici en expressions régulières.


4. Greenpepper avancé


Dans cette partie, vous allez voir comment nous pouvons ajouter la prise en compte de Spring par Greenpepper et comment l'utiliser dans le code des fixtures. 

Afin que Greenpepper prenne en compte le fichier de context de spring, il faut ajouter dans la ligne de commande du Maven Runner l'instruction suivante :

--sud com.monpackage.MonSud;com.monpackage.moncontext1.xml;com.monpackage.moncontext2.xml

Une fois ajouté, Greenpepper est capable de détecter le package de votre SUD (System Under Test : Système testé. Ce package peut être celui de vos services métiers).

Enfin, il faut créer une classe héritant de la classe DefaultSystemUnderDevelopment et implémenter son constructeur comme suit :

MySpringSystemUnderDevelopment :
package com.tutorial.greenpepper.gp.springSud;


public class MySpringSystemUnderDevelopment {

    public MySpringSystemUnderDevelopment(String... applicationCtxes) {
  
        GenericApplicationContext context = new GenericApplicationContext();

        XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(context);

        for (int i = 0; i < applicationCtxes.length; i++) {

            reader.loadBeanDefinitions(applicationCtxes[i]);

        }

        context.refresh();

        beanFactory = context.getBeanFactory();

    }

}

Il est possible de ne mettre qu'un applicationContext en paramètre, ou ne pas en mettre et le spécifier en "dur" dans le constructeur.

Après avoir implémenté cette classe, il faut indiquer son nom (package.nomClasse) dans le champ texte "class name" dans les paramètres avancés de grennpepper dans les propriétés du projet sur Eclipse :


Si le constructeur contient le ou les application context en paramètre, il faut les ajouter dans Constructor args séparés par des ";".

Ceci est suffisant pour que Greenpepper charge votre application context et pour que vos services spring soient injectés.

Dans le code de la partie 3 parlant de l'implémentation, il faudra remplacer l'instanciation des services (ainsi que les dao dans les setup) par un @Autowired.
Il faut faire de même pour GpEntityManager qui est lui même un service Spring.


Conclusion


Dans ce tutorial, vous avez vu comment installer Greenpepper et ce qu'étaient les tests fonctionnels automatisés avec cet outil en rédigeant quelques user stories et en les implémentant.

Les test fonctionnels automatisés sont utilisés le pus souvent dans le cadre des méthodologies agiles. En effet, Grenpepper permet l'expression du besoin par user stories et leur implémentation "itérative".

Ces tests ne remplacent pas les tests unitaires, tests d'intégration, tests de présentation.  Ils testent la couche métier d'une application et vérifie l'adéquation entre le besoin et la réponse au besoin.

Ce ne sont pas non plus seulement des tests de recette car ils peuvent être le reflet de l'application sur une plate-forme de développement, de recette et même en production. Il représentent également des spécifications des user stories exprimées par la MOA.