Introduction à SpecFlow

specflow Bonjour, aujourd’hui nous allons parler de SpecFlow, un petit framework de test que je classerai dans une rubrique de BDD (Behavior Driven Development) puisqu’il propose de faire des tests unitaires en langage courant. L’écriture des tests se divise donc en deux parties : le comportement du test sera écrit par le responsable des spécifications du projet tandis que le pendant technique de ces tests restera à la charge du développeur. Présentation de SpecFlow

Specflow est un petit framework de spécification et de test unitaires.  Sa mission est de faire le pont entre les personnes qui spécifient un projet et ceux qui le développent. Il se base su un principe de BDD : la spécification par l’exemple. Utilisé au lancement d’un projet, il va permettre de définir les comportements souhaités de l’application et ainsi de ne pas développer ce qui n’est pas spécifié. En effet, le projet sera dit terminé quand tous les exemples seront bien implémentés. Il est donc important de bien spécifier les fonctionnalités dès le début, et notamment les cas aux limites qui sont souvent oubliés. Specflow va permettre de créer des tests unitaires à partir de comportements écrits en syntaxe Gherkin, par exemple:

 Feature: SpecFlowFeature
    I want to be told the sum of two numbers

 Scenario: Add two numbers
     Given I have entered 50 into the calculator
     When i typed 10 and press add
     Then the result should be 60 on the screen 

Pour cela, vous allez devoir créer deux types de fichiers :

  1. Les fichiers de Feature où vont être écrits les comportements à tester à l’aide de la syntaxe Gherkin.
  2. Les fichiers de StepDefinitions dans lesquels vont être implémentés les étapes définies dans le fichier de feature

Déjà, un découpage se fait. La personne en charge des spécifications ou des tests va s’occuper des fichiers de Feature tandis que le développeur va s’occuper de leur implémentation en Step Definitions.

La syntaxe Gherkin

Gherkin est le Domain Specific Language de SpecFlow. Cette syntaxe, qui contient très peu de mots clés, se veut compréhensible de tous et est orientée spécification. Ce DSL permet de spécifier un comportement au travers de 3 mots clés:

  1. Given est l’instruction de définition d’un contexte
  2. When est l’instruction qui présente l’action a tester
  3. Then est l’instruction permettant de valider l’action effectuée.

Voici les bases de la syntaxe gherkin. Vous retrouvez la même chose en français:

 Fonctionnalité: Aller à la boulangerie
   Je veux faire verifier que je puisse acheter
   autant de pâtisserie que je veux à la boulangerie

    @Boulangerie
Scénario: Acheter des croissants
    Etant donné que les prix de la boulangerie sont les suivants
       |Nom        | prix  |
       |souris     | 2,5   |
       |croissants | 1     |
    Et que j'ai dans mon portefeuille 20 euros
    Alors je peux acheter 20 croissants 

Etant donné représentant une instruction Given, Quand le When et Alors le Then. Autre chose que je voulais vous montrer avec cet exemple est la faculté de définir rapidement, sous forme de tableau, un jeu de données que ce soit pour initialiser un contexte ou valider un test. Toutes ces phrases ont bien sûr leur pendant en “code”, nécessaire pour pouvoir les interpréter et y dénicher les variables à utiliser. C’est le rôle des Step Definitions que nous allons maintenant aborder.

Les StepDefinitions

Les StepDefinition sont au test unitaire ce que gherkin est à la spécification : une passerelle. Mais voyons à quoi ressemblent les phrases utilisées pour le test anglais:

public class StepDefinition1
{
 // For additional details on
 //SpecFlow step definitions see http://go.specflow.org/doc-stepdef

  [Given("I have entered (.*) into the calculator")]
  public void GivenIHaveEnteredSomethingIntoTheCalculator(int number)
  {
    ScenarioContext.Current["result"] = number;
  }

  [When("i typed (.*) and press add")]
  public void WhenIPressAdd(int number)
  {
    ScenarioContext.Current["result"] = (int) ScenarioContext.Current["result"] + number;
  }

  [Then("the result should be (.*) on the screen")]
  public void ThenTheResultShouldBe(int result)
  {
    Assert.AreEqual(result, (int)ScenarioContext.Current["result"]);
  }
} 

Rien qu’a voir cela, vous avez dû comprendre le truc : chaque phrase va être mappée à une méthode. De plus, chaque phrase peut contenir des arguments qui sont récupérés par expression régulière, comme ici : (.*) . La première expression matchée étant stockée dans le premier argument, la seconde dans le second, etc.. Bien évidement  une méthode peut avoir plusieurs class attributes Then, Given, ou When, et vous pouvez les mixer pour obtenir de belles phrases ! Le ScenarioContext est quant à lui, l’endroit où vous allez pouvoir stocker vos variables pour les utiliser dans d’autres StepDefinitions, méthodes et dans lequel vous allez trouver les informations du contexte d’exécution.

Comment l’installer

Rien de plus simple. Vous aurez besoin de deux composants :

  1. Le package nuget qui vous permettra de générer et lancer les tests
  2. L’extension Visual Studio que vous pouvez aller chercher dans votre gestionnaire d’extension ou ici qui vous permettra d’obtenir l’intégration dans Visual Studio.

Et voilà, à vos features et scénarios !

Les bonus

Maintenant que vous voyez ce qu’est specflow, voyons quelques fonctionnalités que j’ai appréciées lors de mes tests !

Le fichier de config

Un fichier de config de specFlow est a votre disposition. Il vous permet par exemple de choisir un test Runner parmi ceux pris en charge (la liste de compatibilité est ici) ou encore de définir la langue utilisée pour écrire vos fichiers de feature. La configuration se fait simplement. Typiquement, pour utiliser MsTest et utiliser les features en français, il vous faudra configurer votre app.config de la sorte :

<configuration>
  <configSections>
    <section name="specFlow" type="TechTalk.SpecFlow.Configuration.ConfigurationSectionHandler, TechTalk.SpecFlow" />
  </configSections>
  <specFlow>
    <!-- For additional details on SpecFlow configuration
         options see http://go.specflow.org/doc-config -->
    <language feature="fr"></language>
    <unitTestProvider name="MsTest" />
  </specFlow>
</configuration>

Vous pourrez configurer divers paramètres par le biais de ce fichier de config, pour en savoir plus je vous laisse aller vous renseigner ici :  https://github.com/techtalk/SpecFlow/wiki/Configuration

Les hooks

Vous connaissez tous les fameux Class/Method Attributes [ClassInitialize], [TestCleanup] et autres comparses ! Vous serez ravis de savoir que specFlow en met pas mal à votre disposition, notamment sur les scénarios, features ou les Steps eux-mêmes. C’est quand même essentiel. Mais ce que j’ai adoré c’est la possibilité de marquer les scénarios et features avec des tags comme dans les exemples donnés plus haut les @Math ou @Boulangerie. Ces tags vont pouvoir être utilisés conjointement aux hooks pour filtrer une méthode à un ou plusieurs tags de la façon suivante :

[BeforeScenario("boulangerie")]
  public static void BeforeBoulangerieScenario()
  {
    // du code du code du code
  }

Pour en savoir plus sur les hooks et les filtres:  https://github.com/techtalk/SpecFlow/wiki/Hooks

Initialisation de contexte partagé

Nous avons vu que les phrases en Given servaient à initialiser le contexte dans lequel le test va s’exécuter  Si vous effectuez plusieurs fois les mêmes opérations d’initialisation, il est possible de les regrouper au niveau de la feature. Ainsi, vous pourriez avoir un contexte de base, et overrider seulement les données que vous voulez modifier spécifiquement pour un test.


Fonctionnalité: Aller a la boulangerie
    Je veux faire vérifier que je puisse acheter autant de
    pâtisseries que je veux à la boulangerie

@boulangerie
Contexte:
   Etant donné que les prix de la boulangerie sont les suivants
     |Nom        | prix  |
     |souris     | 10,5  |
     |croissants | 1,5   |
     |éclairs    | 1,5   |
     |bonbons    | 0,10  |
     |Tarte      | 15,0  |
     |Baguette   | 1,30  |

Scénario: Acheter des croissants
  Etant donné que les prix de la boulangerie sont les suivants
    |Nom        | prix |
    |souris     | 2,5  |
    |croissants | 1    |
  Et que j'ai dans mon portefeuille 20 euros
  Alors je peux acheter 20 croissants

    

J’ai vraiment trouvé cette possibilité très utile

Tester un projet Web

Ah, j’avais gardé la meilleure fonctionnalité pour la fin : l’intégration avec Sélénium ou watin 😀 Parce que tester une application web peut être assez compliqué si vous n’avez pas les bons outils.

Vous allez avoir deux packages nuget :

  1. Sélénium WebDriver pour pouvoir lancer des tests utilisant un browser
  2. Selenium Support qui contient différentes classes d’aides a l’utilisation du webdriver

Je ne vais pas beaucoup m’étendre dessus mais pour vous montrer que c’est simple, ajoutez  ceci à vos stepDefinitions:

[BeforeScenario()]
public void Setup()
{
   driver = new FirefoxDriver();
}

Et hop un browser se lance !

Ensuite pour naviguer:

driver.Navigate().GoToUrl("http://www.google.fr");

Enfin pour vous faciliter la vie, pensez a utiliser les PageObject qui font partie du package support. Vous pourrez trouver plus d’informations ici:

https://code.google.com/p/selenium/wiki/PageObjects
Enfin voilà, n’hésitez pas à poser des questions dessus, j’y répondrai avec plaisir et je pense que s’il y en a beaucoup sur ce point, je referais un article détaillant plus en détail l’usage de sélénium par son webdriver !

Pour plus d’informations sur cette fonctionnalité:

Sur ce, amusez-vous bien avec specflow et à vos tests, vous n’avez plus d’excuses 🙂 !

Nombre de vue : 1262

COMMENTAIRES 5 commentaires

  1. Raphaël Lemaire dit :

    Interessant, mais qu’est que cette librairie apporte de plus que JBehave, fitnesse avec givwenzen, cucumber, spock, … ?

    Le support selenium pourrait être sympa; on aimerait effectivement en savoir plus 🙂

  2. Ouarzy dit :

    Salut!

    Content de commencer à voir des articles autour du BDD 🙂

    Il y’a juste un point qui me gène dans ton explication: “faire des tests unitaires en langage courant”

    En pratique c’est totalement faux. On a une approche unitaire en terme métier, ce qui dans 95% des cas se traduit par plusieurs TU classique en terme technique.

    D’ailleurs cela se traduit bien par la définition même de “scénario” au sens SpecFlow, c’est un ensemble d’objets sur lequel on va produire des actions pour atteindre un état final.

    Tout l’intérêt est donc de “contextualiser” des TU que tu aurais pu écrire habituellement sans être capable de les mettre en relation avec une fonctionnalité donnée.

    En bref, apporter le métier au plus prêt de la technique!

  3. Vincent Oostenbroek De Lange dit :

    Salut,

    Specflow est une version packagée pour .net. Tout comme semble l’être JBehave pour java.

    Par contre cucumber propose en effet de travailler en .net mais de façon beaucoup moins packagée car il faut dépendre de ruby. C’est d’ailleurs de cela qu’est parti SpecFlow qui se présente bien comme étant inspiré de Cucumber ( “SpecFlow was inspired by Cucumber and is using Gherkin” )

    Après je ne connaissait pas spock ni givwenzen mais il semble que ce soient des outils pour java. De plus à première vue, pour givwenzen, la syntaxe gherkin a l’air plus lourde avec les pipe autour des given, when et then.

    Et pour le support selenium, je vais essayer de faire un petit article sur son intégration dans .net avec les webdriver. 🙂 Mais globalement, les points à voir sont:
    – les profils ( empêcher firefox de faire ses mises a jour, …)
    – les PageObjects qui permettent de preparer les différentes actions sur les pages

    A part ces deux points, rien de compliqué, c’est pour cela que je ne savais pas si il y avait matière à faire un article complet.

  4. Vincent Oostenbroek De Lange dit :

    Salut ouarzy,

    Pour le langage courant, oui et non. Il est évident que pour définir le comportement d’une application il faut en connaitre le domaine et son vocabulaire.
    J’ai utilisés le terme de langage courant puisque cela reste du français et non du code. C’est compréhensible par une personne fonctionnelle.

    Donc oui tu as raison dans le sens ou une personne externe au domaine aura surement du mal a comprendre le test unitaire si elle ne connait pas le vocabulaire. Par contre si le test n’est pas compréhensible pour une personne ayant cette connaissance, il n’y a aucun bénéfice à utiliser specflow.

    Le but est surtout de permettre a une personne non développeuse de vérifier que tout les cas qu’elle souhaite implémentés sont bien testés. Que ce soit une fonctionnalité, une parti de celle ci ou l’enchaînement de plusieurs.

    Mais pour finir, je dirais que specflow reste un outil, il sera toujours possible de l’utiliser de différente facon, plus techniques ou plus fonctionnelle, tout dépendra finalement de la personne qui l’utilisera.

  5. […] Article « Introduction à Specflow » sur le blog de Soat pour aborder l’automatisation des scénario http://blog-rec.soat.fr/2013/04/introduction-a-specflow/ […]

AJOUTER UN COMMENTAIRE