BDD, Behat, Gherkin – Introduction au Behavior Driven Development avec Behat et Mink
Le développement piloté par le comportement, voilà la traduction forcement moins attirante que sa définition première en anglais : “Behavior Driven Development”. Plus encore le mot comportement est sans doute plus sexy que le mot test. Pour qui s’agite à l’audition des mots Agile ou Lean, vous avez déjà du avoir les oreilles qui bourdonnent à des mots tel que : Behat, Gherkin pour ne citer que ces 2 termes.
Si vous vous intéressez au développement que ce soit mobile ou web, la nécessité d’intégrer des tests fonctionnels via Behat est quasi une obligation. Dans le cas par exemple du développement en PHP, sous les frameworks Symfony ou Laravel, cela vous sera systématiquement demandé.
Un extrait plutôt censé du blog de Dan North sur l’importance du behaviour-driven development (BDD)
It has evolved out of established agile practices and is designed to make them more accessible and effective for teams new to agile software delivery. Over time, BDD has grown to encompass the wider picture of agile analysis and automated acceptance testing.
Ce qui est extrêmement intéressant c’est que vous forgez une approche transverse et un “langage” commun avec l’ensemble des parties prenantes de votre projet de développement : le client (product-owner), la direction de projet, l’équipe de développement. Bien évidemment, les “user stories” peuvent être rédigées de la même manière. Un des points essentiels avec l’utilisation du Gherkin, c’est qu’il peut vous aider à faire toute la lumière sur ce que vous considérez comme implicite afin de le rendre explicite. Le BDD est aussi une manifestation pratique dans le management agile, instituant l’implication de chacun donc la cohésion du groupe, au même titre que les traditionnels rituels agile.
Dan North donne un exemple très parlant de cette exhaustivité lié à l’usage du Gherkin pour décrire des user stories sur un exemple aussi banal que le retrait d’argent à un distributeur avec une carte. L’usage du Gherkin en décomposant cette simple action en une suite logique permet de ne rien omettre sur les conditions de bonne ou de mauvaise exécution.
L’exemple en langage commun
+Title: Customer withdraws cash+
As a customer, I want to withdraw cash from an ATM, so that I don’t have to wait in line at the bank.
En utilisant le modele “given-when-then”, la complexité éventuelle d’une action aussi anodine s’éclaire tour à coup.
+Scenario 1: Account is in credit+
Given the account is in credit And the card is valid And the dispenser contains cash When the customer requests cash Then ensure the account is debited And ensure cash is dispensed And ensure the card is returned
A noter que l’usage intensif de la conjonction “and” permet de connecter plusieurs “givens” ou plusieurs résultats d’une manière intuitive.
+Scenario 2: Account is overdrawn past the overdraft limit+
Given the account is overdrawn And the card is valid When the customer requests cash Then ensure a rejection message is displayed And ensure cash is not dispensed And ensure the card is returned
Source : https://dannorth.net/introducing-bdd/
Mink Behat & the tests
Laissons tomber le volet théorique, vous s’attelez à la pratique. L’ensemble des exemples ci-dessous ont été menés dans l’environnement suivant : Firefox 47.0, une version de PHP 5.5.38 avec l’aide de la console.
Vous aurez besoin de homebrew, d’installer composer sir ce n’est pas déjà fait. Il y a eu quelques difficultés agaçantes que vous aurez peut-être à résoudre éventuellement.
1. Problème de timezone dans PHP
Il y avait des erreurs de date lors de l’exécution des tests, sans gravité mais troublant. Le problème venait du fait que la “timezone” n’était pas définie dans le php.ini
.
Les commandes de base pour localiser et modifier le php.ini
php -v # check la version php --ini # localise le fichier php.ini vi /usr/local/etc/php/5.5/php.ini # editer le fichier php.ini |
Extrait du php.ini à modifier
;;;;;;;;;;;;;;;;;;; ; Module Settings ; ;;;;;;;;;;;;;;;;;;; [CLI Server] ; Whether the CLI web server uses ANSI color coding in its terminal output. cli_server.color = On [Date] ; Defines the default timezone used by the date functions ; http://php.net/date.timezone ;date.timezone = date.timezone = Europe/Paris |
2. Installer geckodriver
Autre souci, plus ennuyeux, pour installer geckodriver, le plus simple est de passer par Homebrew avec la commande suivante.
brew install geckodriver
3. La commande pour lancer pour lancer le serveur selenium si vous souhaitez faire des tests dans un navigateur firefox
java -jar /chemin-vers-le-fichier/selenium-server-standalone-3.0.0-beta3.jar
Source : Selenium Standalone Server http://goo.gl/EUxR76
La marche à suivre
La première chose à faire consiste créer un répertoire dans lequel vous allez effectuer vos travaux. Le notre se nomme demo-2
Pour vous faciliter la tache, voilà une video youtube très didactique, qui a servi de base à ce billet.
La source du fichier composer.json qui vous permettra d’installer les éléments nécessaires aux tests dans votre répertoire. Notre projet se nomme demo-2. cd /chemin-vers-votre-projet-behat/demo-2/
puis composer install
{ "require": { "behat/mink": "1.4@stable", "behat/mink-goutte-driver": "*", "behat/mink-selenium2-driver": "*", "behat/behat": "2.4@stable", "behat/mink-extension": "*", "guzzle/guzzle": "3.5", "moodlehq/behat-extension": "1.*" }, "minimum-stability": "dev", "config": { "bin-dir": "bin/" } } |
Une fois le tout installer, voilà les principales commandes dont vous aurez besoin. Toutes ces commandes sont à passer dans le répertoire du projet demo-2
.
php bin/behat --init # créer le nécessaire pour behat php bin/behat # pour lancer vos tests avec behat php bin/behat -dl # pour connaitre toutes les règles de mink pour ecrire vos .feature |
Le fichier search.feature
pour tester la recherche du site Le monde
# Content of file renting.feature Feature: Search In order to find a word As website user I am able to search for a word # avec le @javascript vous lancez le test dans le navigateur firefox # sans le @javascript vous faites passer le test en mode headless. @javascript Scenario: Search for a word that exists Given I am on "http://www.lemonde.fr/" When I fill in "recherche_globale" with "ONU" And I press "rechercher" Then I should see "la situation à Alep" |
L’installation des éléments via la composer
Le test en mode headless
L’inspecteur de Chrome vous permet de connaitre les éléments id|name|label|value à placer dans votre scénario de test.
Quelques commandes pour faire une sortie sous forme de rapport html des résultats de vos tests
php bin/behat --format html --out report.html php bin/behat -f pretty,progress,junit --out ,progress.out,xml |
La sortie complète des actions avec la commande php bin/behat -dl
When /^I click "([^"]*)"$/ Given /^I wait for (\d+) seconds$/ When I wait for :arg1 seconds Given /^I wait for "([^"]*)" seconds$/ Given /^(?:|I )am on (?:|the )homepage$/ When /^(?:|I )go to (?:|the )homepage$/ Given /^(?:|I )am on "(?P<page>[^"]+)"$/ When /^(?:|I )go to "(?P<page>[^"]+)"$/ When /^(?:|I )reload the page$/ When /^(?:|I )move backward one page$/ When /^(?:|I )move forward one page$/ When /^(?:|I )press "(?P<button>(?:[^"]|\\")*)"$/ When /^(?:|I )follow "(?P<link>(?:[^"]|\\")*)"$/ When /^(?:|I )fill in "(?P<field>(?:[^"]|\\")*)" with "(?P<value>(?:[^"]|\\")*)"$/ When /^(?:|I )fill in "(?P<value>(?:[^"]|\\")*)" for "(?P<field>(?:[^"]|\\")*)"$/ When /^(?:|I )fill in the following:$/ When /^(?:|I )select "(?P<option>(?:[^"]|\\")*)" from "(?P<select>(?:[^"]|\\")*)"$/ When /^(?:|I )additionally select "(?P<option>(?:[^"]|\\")*)" from "(?P<select>(?:[^"]|\\")*)"$/ When /^(?:|I )check "(?P<option>(?:[^"]|\\")*)"$/ When /^(?:|I )uncheck "(?P<option>(?:[^"]|\\")*)"$/ When /^(?:|I )attach the file "(?P[^"]*)" to "(?P<field>(?:[^"]|\\")*)"$/ Then /^(?:|I )should be on "(?P<page>[^"]+)"$/ Then /^the (?i)url(?-i) should match (?P<pattern>"([^"]|\\")*")$/ Then /^the response status code should be (?P<code>\d+)$/ Then /^the response status code should not be (?P<code>\d+)$/ Then /^(?:|I )should see "(?P<text>(?:[^"]|\\")*)"$/ Then /^(?:|I )should not see "(?P<text>(?:[^"]|\\")*)"$/ Then /^(?:|I )should see text matching (?P<pattern>"(?:[^"]|\\")*")$/ Then /^(?:|I )should not see text matching (?P<pattern>"(?:[^"]|\\")*")$/ Then /^the response should contain "(?P<text>(?:[^"]|\\")*)"$/ Then /^the response should not contain "(?P<text>(?:[^"]|\\")*)"$/ Then /^(?:|I )should see "(?P<text>(?:[^"]|\\")*)" in the "(?P<element>[^"]*)" element$/ Then /^(?:|I )should not see "(?P<text>(?:[^"]|\\")*)" in the "(?P<element>[^"]*)" element$/ Then /^the "(?P<element>[^"]*)" element should contain "(?P<value>(?:[^"]|\\")*)"$/ Then /^the "(?P<element>[^"]*)" element should not contain "(?P<value>(?:[^"]|\\")*)"$/ Then /^(?:|I )should see an? "(?P<element>[^"]*)" element$/ Then /^(?:|I )should not see an? "(?P<element>[^"]*)" element$/ Then /^the "(?P<field>(?:[^"]|\\")*)" field should contain "(?P<value>(?:[^"]|\\")*)"$/ Then /^the "(?P<field>(?:[^"]|\\")*)" field should not contain "(?P<value>(?:[^"]|\\")*)"$/ Then /^the "(?P<checkbox>(?:[^"]|\\")*)" checkbox should be checked$/ Then /^the "(?P<checkbox>(?:[^"]|\\")*)" checkbox should not be checked$/ Then /^(?:|I )should see (?P<num>\d+) "(?P<element>[^"]*)" elements?$/ Then /^print last response$/ Then /^show last response$/ |
En savoir plus
- Quick intro to behat
http://docs.behat.org/en/v2.5/quick_intro.html - Le compte geckodriver sur github
https://github.com/mozilla/geckodriver/releases - Une checklist pour l’installation de Selenium WebDriver
https://github.com/eviltester/startUsingSeleniumWebDriver/blob/master/speedrun_install_checklist.txt - Définition du Headless browser
https://en.wikipedia.org/wiki/Headless_browser - La page de téléchargements de seleniumhq
http://www.seleniumhq.org/download/ - La fichier composer du compte de Weaver Ryan
https://gist.github.com/weaverryan/5987090 - Vidéo – BDD, Behat, Mink & other Wonderful Things
https://www.youtube.com/watch?v=BVVk4FbbCaA - Vidéo – How to start firefox Browser in Selenium webdriver 3 with Gecko Driver
https://www.youtube.com/watch?v=rJ4rNZGAzW8 - The Mink documentation
http://mink.behat.org/en/latest/ - Doing Behavior Driven Development in PHP with Behat
http://www.developer.com/lang/php/doing-behavior-driven-development-in-php-with-behat.html - BDD avec Behat
https://www.grafikart.fr/tutoriels/php/behaviour-driven-development-behat-552 - Chapitre 4 Automatisez votre recette – Le développement piloté par le comportement
http://communiquez.lepine.pro/download/developpement-pilote-par-le-comportement-tome2/chapitre-4.html - Vidéo – Quickstart to testing your website with Behat, Mink, and Selenium
https://www.youtube.com/watch?v=9cYhnTojaHU - Les fichiers pour la video : Quickstart to testing with Behat, Mink, and Selenium
http://lin-clark.com/blog/2013/11/26/quickstart-testing-with-behat-mink-selenium/ - Automated Testing with Cucumber and Capybara
http://www.gamesparks.com/blog/automated-testing-with-cucumber-and-capybara/ - Setting up Cucumber on OSX par Paradigm IT Consulting
http://www.paradigmitconsulting.com/setting-up-cucumber-on-osx/ - Command Line Tool – behat
http://docs.behat.org/en/v2.5/guides/6.cli.html - The 5 Step Guide for Selenium, Cucumber, and Gherkin
http://www.agiletrailblazers.com/blog/the-5-step-guide-for-selenium-cucumber-and-gherkin - Is Your Test Automation Portfolio Ready For Acceleration? Or Will It Slow You Down?
http://www.agiletrailblazers.com/blog/is-your-test-automation-portfolio-ready-for-acceleration-or-will-it-slow-you-down-2/ - Write Great Cucumber Tests
http://sauceio.com/index.php/tag/cucumber/ - iOS Automated Testing in the BDD with Cucumber, Appium and SauceLabs (excellent)
http://shashikantjagtap.net/ios-automated-testing-in-the-bdd-with-appium-cucumber-on-mac-osx/ - Cucumber: Getting started par James Chambers
http://jameschambers.co/writing/cucumber-for-beginners-getting-started/ - Behat – jour 3 : Tester une application web avec Mink par Jean-François Lépine
http://blog.lepine.pro/php/behat-jour-3-tester-une-application-web-avec-mink/ - Behat and Mink (simple et didactique)
https://knpuniversity.com/screencast/behat-v25/mink-behat - Test Design Considerations
http://www.seleniumhq.org/docs/06_test_design_considerations.jsp - Page Object Model | POM
http://toolsqa.com/selenium-webdriver/page-object-model/ - Page Object Model (POM) & Page Factory in Selenium: Ultimate Guide
http://www.guru99.com/page-object-model-pom-page-factory-in-selenium-ultimate-guide.html - ROBOT FRAMEWORK, Generic test automation framework for acceptance testing and ATDD
http://robotframework.org/ - Apprenez le Gherkin pour écrire vos User Stories
http://blog.thiga.fr/product-management/bdd-gherkin-pour-ecrire-vos-user-stories/ - Le Story Mapping, notre retour d’expérience
http://blog.thiga.fr/product-management/story-mapping-notre-retour-dexperience/ - Cucumber
https://cucumber.io/ - Tout savoir (ou presque) sur le Behaviour Driven Development (BDD)
http://coding-in.net/fr/tout-savoir-ou-presque-sur-le-behaviour-driven-development-bdd/ - Chapitre 3 – Comprenez (enfin!) ce que votre client vous demande – Le développement piloté par le comportement
http://communiquez.lepine.pro/download/developpement-pilote-par-le-comportement-tome2/chapitre-3.html - Testing your Symfony application with behat
http://www.pix-art.be/post/testing-your-symfony-application-with-behat - Top 15 TextMate Shortcuts, toujours utile
http://www.benrasmusen.com/featured/top-15-textmate-shortcuts/