Accueil Nos publications Blog Introduction à SpecFlow

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 https://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 https://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("https://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 🙂 !