mardi 15 mai 2012

JBehave, pour du BDD en Java

J'ai récemment entendu parler de JBehave, une librairie java très utile pour mettre en place du BDD sur son projet; Mais tout d'abord, je vais tenter d'introduire le BDD, domaine que je découvre.
Cet article sera avare en code mais vous trouverez un lien vers un projet github mettant en pratique JBehave en fin d'article.



BDD, et non BDD (aucun rapport)
Et non, en parlant de BDD nous n'aborderons pas le sujet des Bases De Donnée; Nous allons plutôt parler ici de Behavior Driven Development.

Depuis bientôt 2 ans je développe autant que possible en TDD (Test Driven Development), méthode consistant à écrire les test unitaires avant d'écrire le code de production: Cela a pour avantage :
- de valider que le test ne passe pas en cas d'anomalie dans le code
- d'augmenter la couverture des tests, car en TDD il est interdit d'écrire du code si l'on a pas écrit le test correspondant.
- de concevoir: écrire le test avant nous fait réfléchir à "comment utiliser la fonction que je veux coder". Cela permet donc de faire des API mieux conçues.

Alors le TDD c'est bien, mais comme tout ce qui touche à l'XP, ça reste un "truc de techos" comme on dis, et ce n'est pas toujours comprit par le reste de l'équipe projet et ils ont du mal à voir ce que ça leur apporte.

Le BDD, pour moi, va avoir l'avantage d'impliquer les fonctionnels de l'équipe projet.
Le BDD, c'est écrire les test d’acceptance au début du projet par le biais de scénarios. Utiliser un certain formalisme concis permet aussi d'avoir une vision claire des règles métier.
Le formalisme utilisé est en général celui ci:

Scenario 1:  An user search documents

Given a list of 5 documents
Given an simple user
When the user search with the value *
Then he retrieve 5 documents

On écrit les conditions initiales, puis l'action à tester, et on finit avec la vérification du résultat.

Le format est concis, et permet une communication efficace entre les divers corps de métiers: MOA,développeurs,testeurs.

JBehave
Du Behave pour J
JBehave est une librairie java que l'on peut trouver ici: http://jbehave.org/ et qui permet de transformer vos scénarios en tests automatisés.

Concrètement cela consiste en la mise en place de tests Junit, dans lesquels chaque phrase utilisée dans les scénarios correspond à une fonction. Le lien est fait via annotations.

Par exemple:
Given a list of 5 documents
Pourra se traduire par :

@Given("a list of $nbDoc documents")
public void initDocumentList(int nbDoc){

       docs=new ArrayList<Document>();
       for(int i=0;i<nbDoc;i++){
                docs.add(generateRandomDocument());
       }
}

Il est possible, pour un même scénario, d'utiliser plusieurs phrases d'initialisation ou d'action:
Given a condition 1
Given a condition 2
Given another condition 1

When do action
When do another action
Then something happen

De même il est possible d'avoir le choix entre plusieurs résultats escomptés:
Then result=5
ou
Then error message appear
pour tester les cas d'erreur.

Il est d'ailleurs possible d'alléger la syntaxe en utilisant le mot clés And :

Given a condition 1
And a condition 2
And another condition 1
When do action
And do another action
Then something happen


Dans la langue de l'équipe


Il est possible de travailler dans la langue natale de l'équipe grâce à l’internationalisation des mots clés.
JBehave supporte déjà une dizaine de langues nativement tel que anglais, français, allemand, italien, ect.
En français pas exemple, les mots clés sont les suivants:

Given=Etant donné que
When=Quand
Then=Alors

La totalité des mots clés se trouve ici: keywords_fr.properties

Si les mots clés ne conviennent pas (par exemple si vous souhaitez utiliser Etant donné à la place de Etant donné que), il est possible de les customiser, en créant un fichier keyword_xx.properties que l'on placera dans src/test/resources/i18n/.
Ce qui donnera dans l'exemple précèdent:

Etant donné une liste de 5 documents

@Given("une liste de $nbDoc documents")
public void initDocumentList(int nbDoc){
    // le même code qu'avant
}



Convertir vos phrases en Objets

Afin de mutualiser la transformation des paramètres (initialement des String) en objet Java non pris en charge, il vous faudra utiliser des converters.
Par exemple, si nous avons un projet avec des drones, une classe Position et que l'on souhaite pouvoir initialiser la Position d'un drone pour nos tests.
Nous allons donc écrire le converter suivant:

/**
 * 
 */
package com.mowitnow.mower.jbehave;

import java.lang.reflect.Type;

import org.jbehave.core.steps.ParameterConverters.ParameterConverter;

import com.mowitnow.mower.position.Cardinal;
import com.mowitnow.mower.position.Position;

/**
 * @author cafetux
 * a converter for Position.
 */
public class PositionConverter implements ParameterConverter {

 public boolean accept(Type type) {
  if(type.equals(Position.class)){
   return true;
  }
  return false;
 }

 public Object convertValue(String value, Type type) {
  Position pos=null;
  int x,y;
  String[] values = value.split(" ");
  x=Integer.valueOf(values[0]);
  y=Integer.valueOf(values[1]);
  String o=values[2];
  Cardinal orientation = Cardinal.getByName(o.toUpperCase());
  pos=new Position(x, y, orientation);
  return pos;
 }

}

Nous allons rajouter ce converter dans notre configuration :

@Override
public Configuration configuration() {
   Properties viewResources = new Properties();
   viewResources.put("decorateNonHtml", "true");
         
   LocalizedKeywords keywords = new LocalizedKeywords(new Locale("fr"));
   return new MostUsefulConfiguration().useParameterConverters(new ParameterConverters()
   .newInstanceAdding(new PositionConverter()))
   .useKeywords(keywords)
   .useStoryParser(new RegexStoryParser(keywords))
   .useStoryLoader(new  LoadFromClasspath(getClass().getClassLoader()))
   .useStoryReporterBuilder(
                new StoryReporterBuilder()
                .withDefaultFormats()
                .withViewResources(viewResources)
                .withFormats(Format.CONSOLE, Format.TXT, Format.HTML, Format.XML)
                .withFailureTrace(true).withFailureTraceCompression(true));
  }


Première impression


JBehave devrait pouvoir se mettre en place facilement sur un projet car :
       - L'équipe rédactrice des tests peut écrire dans la langue qu'elle souhaite avec les mots clés choisis.
       - Les développeurs peuvent l'adopter facilement car JBehave s’intègre naturellement dans un projet Maven qui utilise Junit.
 
Il n'y a donc pas à s'adapter pour l'utiliser.

Si vous avez des retours pour l'avoir utilisé sur un projet, je suis preneur.

Les sources du projet dont je me suis servis pour tester JBehave sont sur github.

Aucun commentaire:

Enregistrer un commentaire

Crédits

Thème dérivé du GUI Set Retro-pixel.