Drupal camp paris 2013: présentation de Behat, Mink et Drupal extension
Upcoming SlideShare
Loading in...5
×
 

Drupal camp paris 2013: présentation de Behat, Mink et Drupal extension

on

  • 1,645 views

Introduction aux tests de recette automatisés avec l'extension Drupal pour Behat

Introduction aux tests de recette automatisés avec l'extension Drupal pour Behat

Statistics

Views

Total Views
1,645
Views on SlideShare
1,483
Embed Views
162

Actions

Likes
0
Downloads
21
Comments
0

2 Embeds 162

http://paris2013.drupalcamp.fr 147
https://twitter.com 15

Accessibility

Categories

Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

Drupal camp paris 2013: présentation de Behat, Mink et Drupal extension Drupal camp paris 2013: présentation de Behat, Mink et Drupal extension Presentation Transcript

  • Introduction aux tests de recette automatisésAvec lextension Drupal pour Behatdidier.boff@ows.frB2F @ drupal.orghttps://github.com/B2Fhttp:///twitter.com/zenelse
  • Les joies du testQuand mon collègue avance sans plan de testhttp://lesjoiesdutest.tumblr.com
  • Plan● Retour dexpérience○ Campus France○ Divers outils démodés
  • Plan● Retour dexpérience○ Campus France○ Divers outils démodés● Méthodologie○ BDD, Gherkin
  • Plan● Retour dexpérience○ Campus France○ Divers outils démodés● Méthodologie○ BDD, Gherkin● Développement○ Behat/Mink○ MinkExtension (démo)○ DrupalExtension (démo)
  • Retour dexpériencewww.campusfrance.org● Migration Drupal 6 -> 7
  • Retour dexpériencewww.campusfrance.org● Migration Drupal 6 -> 7● 100 sites, domain access● multilingues
  • Retour dexpériencewww.campusfrance.org● Migration Drupal 6 -> 7● 100 sites, domain access● multilinguesQuels tests ?
  • Retour dexpérienceSeleniumAPI● click● type● select● addSelection● submit● ... http://release.seleniumhq.org/selenium-core/
  • Retour dexpérienceSeleniumIDE
  • Retour dexpérience?Test automatiséSeleniumIDE
  • Retour dexpérienceSeleniumIDE?Test automatiséMultidomaine
  • Retour dexpérienceSeleniumIDE?AJAXMultidomaineTest automatisé
  • Retour dexpérienceSelenium Serverhttp://docs.seleniumhq.org/download/java -jar selenium-server-standalone-<version-number>.jarhttp://selenium.googlecode.com/files/selenium-server-standalone-2.33.0.jar
  • Retour dexpérienceSelenium Server+ PHPUnitPHPUnit_Extensions_SeleniumTestCase
  • Retour dexpérienceSelenium Server+ PHPUnithttps://github.com/B2F/ows-phpunitclass OWSeleniumTestCase extendsPHPUnit_Extensions_SeleniumTestCase {public function __construct($name = NULL, array $data = array(),$dataName = ) {
  • Retour dexpérienceSelenium Server+ PHPUnit+ IDE
  • Retour dexpérienceSelenium Server+ PHPUnit+ IDE+Selenium IDE: PHP Formattershttps://github.com/brokenthumbs/PHP-Formatter
  • Retour dexpérienceSelenium Server+ PHPUnit+ IDE+Selenium IDE: PHP Formattershttps://github.com/brokenthumbs/PHP-Formatterhttps://github.com/B2F/PHP-Formatter
  • Les joies du testQuand je fais un test un peu trop compliqué pour un tructout simplehttp://lesjoiesdutest.tumblr.com
  • Les joies du testQuand je fais un test un peu tropcompliqué pour un truc tout simple ?
  • Les joies du testQuand je fais un test un peu tropcompliqué pour un truc tout simple
  • Les joies du testQuand je fais un test un peu tropcompliqué pour un truc tout simple19 content types
  • Les joies du testQuand je fais un test un peu tropcompliqué pour un truc tout simple...
  • Méthodologie● Behavior Driven Development (BDD)
  • Méthodologie● Behavior Driven Development (BDD)DrupalCon Portland 2013: BEHAT, BEHAVIORAL-DRIVEN DEVELOPMENT AND SELENIUM IN DRUPALRyan Weaverhttps://portland2013.drupal.org
  • Méthodologie● Gherkin
  • Méthodologie● Gherkin● Feature Suite de tests
  • Méthodologie● Gherkin● Feature○ Scenario Test
  • Méthodologie● Gherkin● Feature○ Scenario■ Given● And...Contexte
  • Méthodologie● Gherkin● Feature○ Scenario■ Given● And...ContexteGiven I am on "/restaurants"
  • Méthodologie● Gherkin● Feature○ Scenario■ Given● And...■ When● And...Évènements
  • Méthodologie● Gherkin● Feature○ Scenario■ Given● And...■ When● And...ÉvènementsAnd I enter "Vietnam" for "pays"And I enter "Bo Bun" for "plats"And I enter "Paris 13" for "lieu"
  • Méthodologie● Gherkin● Feature○ Scenario■ Given● And...■ When● And...■ Then● And...RésultatsThen I should see the text "Pho Bida"
  • Opened Blackbox● CucumberGherkin + Ruby
  • Opened Blackbox● Cucumber=Gherkin + Ruby
  • Opened Blackbox● CucumberGherkin + Ruby ?
  • Opened Blackbox● CucumberGherkin + PHP
  • Opened Blackbox● Behathttp://behat.org/=Gherkin + PHP
  • Opened Blackboxhttp://behat.org/<?phpuse BehatBehatContextBehatContextclass FeatureContext extends BehatContext{// /**// * @Given /^I have done something with "([^"]*)"$/// */// public function iHaveDoneSomethingWith($argument)// {// doSomethingWith($argument);// }}● Behat: ça fait quoi ?
  • Opened Blackboxhttp://behat.org/<?phpuse BehatBehatContextBehatContextclass FeatureContext extends BehatContext{// /**// * @Given /^I have done something with "([^"]*)"$/// */// public function iHaveDoneSomethingWith($argument)// {// doSomethingWith($argument);// }}● Behat: ça fait quoi ?
  • Opened Blackbox● MinkWeb acceptance testinghttp://mink.behat.org/
  • Opened Blackbox● Mink: drivers$driver = new BehatMinkDriverZombieDriver();http://mink.behat.org/
  • Opened Blackbox● Mink: drivers$driver = new BehatMinkDriverSahiDriver(firefox);http://mink.behat.org/
  • Opened Blackbox● Mink: drivers$driver = new BehatMinkDriverGoutteDriver();http://mink.behat.org/
  • Opened Blackbox● Mink: drivers$client = new SeleniumClient($host, $port);$driver = new BehatMinkDriverSeleniumDriver(firefox, base_url, $client);http://mink.behat.org/
  • Opened Blackbox● Mink: session// init session:$session = new BehatMinkSession($driver);// start session:$session->start();http://mink.behat.org/$session->visit(http://paris2013.drupalcamp.fr);
  • Opened Blackbox● Mink: méthodes$page = $session->getPage();$element = $page->find(css, a#selector);$element->getText();http://mink.behat.org/
  • Opened Blackbox● Mink: méthodes$page = $session->getPage();$element = $page->find(css, a#selector);$element->getText();http://mink.behat.org/
  • Développement● En pratiquehttp://mink.behat.org/Behat + Mink ?
  • Développement● Mink extensionhttp://mink.behat.org/=Behat + Mink
  • Développement● Mink extensionhttp://mink.behat.org/STEPS
  • Développement● Mink extensionhttp://mink.behat.org/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<field>(?:[^"]|")*)" with:$/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>(?:[^"]|")*)"$/...bin/behat -dl
  • Développement● Mink extensionhttp://mink.behat.org/Presses button with specified id|name|title|alt|value.@When /^(?:|I )press "(?P<button>(?:[^"]|")*)"$/Clicks link with specified id|title|alt|text.@When /^(?:|I )follow "(?P<link>(?:[^"]|")*)"$/Behat/MinkExtension/Context/MinkContext.php
  • DéveloppementInstallationhttp://docs.behat.org/#cookbookDeveloping Web Applications with Behat and Mink
  • DéveloppementInstallationcomposer.json{"require": {"behat/behat": "2.4.*@stable","behat/mink": "1.4.*@stable","behat/mink-extension": "*","behat/mink-goutte-driver": "*","behat/mink-selenium2-driver": "*"},"minimum-stability": "dev","config": {"bin-dir": "bin/"}} http://docs.behat.org/cookbook/behat_and_mink.html
  • DéveloppementInstallation$ curl http://getcomposer.org/installer | php$ php composer.phar installhttp://docs.behat.org/cookbook/behat_and_mink.html
  • DéveloppementInstallation$ lsbin composer.json composer.lock composer.phar vendorhttp://docs.behat.org/cookbook/behat_and_mink.html
  • DéveloppementInstallation$ bin/behat --init-> features/
  • DéveloppementInstallation: suites de testsfeatures/{name}.featureFeature: un exempleQuelques steps pour illustrer une featureScenario: vérification quun lien est présentGiven I am at "/home"When I click "Se connecter"Then I should see "login"
  • DéveloppementInstallation: customisation$ bin/behat --init-> features/bootstrap/FeatureContext.php
  • DéveloppementInstallation: customisation# features/bootstrap/FeatureContext.php/*** Features context.*/class FeatureContext extends BehatContext{...
  • DéveloppementInstallation: customisation# features/bootstrap/FeatureContext.php/*** Features context.*/class FeatureContext extends BehatContext{...
  • DéveloppementInstallation: customisation# features/bootstrap/FeatureContext.php/*** Features context.*/class FeatureContext extends MinkContext{...
  • DéveloppementInstallation: subcontexts# features/bootstrap/FeatureContext.phpuse BehatMinkExtensionContextRawMinkContext;use BehatMinkExtensionContextMinkContext;class FeatureContext extends RawMinkContext{public function __construct(array $parameters){$this->useContext(mink, new MinkContext);}}http://extensions.behat.org/mink/
  • DéveloppementInstallation: subcontexts# features/bootstrap/FeatureContext.phpuse BehatMinkExtensionContextRawMinkContext;use BehatMinkExtensionContextMinkContext;class FeatureContext extends RawMinkContext{public function __construct(array $parameters){$this->useContext(mink, new MinkContext);}}http://extensions.behat.org/mink/
  • Développement● Mink stepsWhen will this be over ?http://mink.behat.org/
  • Développement● Mink stepsWhen I hover the element ?/*** @When /^I hover "([^"]*)"$/*/public function iHover($cssId){http://mink.behat.org/When will this be over ?
  • Développement● Mink steps/*** @When /^I hover "([^"]*)"$/*/public function iHover($cssId){$page = $this->getSession()->getPage();$element = $page->find(css, $cssId);http://mink.behat.org/api/behat/mink/element/nodeelement.html
  • Développement● Mink stepspublic function iHover($cssId){$page = $this->getSession()->getPage();$element = $page->find(css, $cssId);if (null === $element) {throw new ElementNotFoundException($this->getSession(), element, css, $}http://mink.behat.org/api/behat/mink/element/nodeelement.html
  • Développement● Mink steps__construct(Session session, string type, string selector, string locator)And I hover "a[title=abcdefghi]" # FeatureContext::iHover()Element matching css "a[title=abcdefghi]" not found.throw new ElementNotFoundException($this->getSession(), element, css, $cssId);http://mink.behat.org/api/behat/mink/element/nodeelement.html
  • Développement● Mink stepspublic function iHover($cssId){$page = $this->getSession()->getPage();$element = $page->find(css, $cssId);if (null === $element) {throw new ElementNotFoundException($this->getSession(), element, css, $cssId}$element->mouseOver();http://mink.behat.org/api/behat/mink/element/nodeelement.html
  • Développement● Mink stepspublic function iHover($cssId){$page = $this->getSession()->getPage();$element = $page->find(css, $cssId);if (null === $element) {throw new ElementNotFoundException($this->getSession(), element, css, $cssId}$element->mouseOver();Attention: Selenium supporte lemouseOver Javascript only :(http://mink.behat.org/api/behat/mink/element/nodeelement.html
  • Développement● Mink steps - AJAX/*** Waits some time or until JS condition turns true.** @param integer $time time in milliseconds* @param string $condition JS condition*/public function wait($time, $condition = false){$this->driver->wait($time, $condition);}http://mink.behat.org/api/source/behat/mink/session.php.html
  • Développement● Mink steps - AJAX/*** @When /^I wait (?P<timing>d+)sec$/*/public function iWaitNSec($timing) {$this->getSession()->wait($timing*1000);}http://mink.behat.org/api/source/behat/mink/session.php.html
  • Développement● Mink steps - AJAX/*** @When /^I wait (?P<timing>d+)sec$/*/public function iWaitNSec($timing) {$this->getSession()->wait($timing*1000);}http://mink.behat.org/api/source/behat/mink/session.php.html
  • DéveloppementDémobin/behat features/demo.feature
  • DéveloppementDémo: colored outputbin/behat --ansi features/demo.featurebehat arguments: http://docs.behat.org/guides/6.cli.html
  • Développement● OwsContexthttps://github.com/B2F/OwsContextpublic function iHover($cssId)public function iWaitNsec($timing)public function iClickTheElementMatching($selector)
  • Développement● OwsContexthttps://github.com/B2F/OwsContext+ (experimental)public function iWaitNSecForTheText($timing, $text)public function iSwitchToTheIframeNamed($iframe)public function iSwitchBackFromIframe()
  • DéveloppementConfiguration# behat.ymldefault:extensions:BehatMinkExtensionExtension:base_url: http://google.frgoutte: ~selenium2: ~
  • DéveloppementConfiguration● AJAX@javascriptScenario: vérification quun lien est présentGiven I am at "/home"When I follow "my account"Then I should see "my page title"
  • DéveloppementConfiguration● Profiles = overrides# behat.ymldefault:...custom:extensions:BehatMinkExtensionExtension:base_url: http://another-url.com
  • DéveloppementConfiguration● Profiles# bin/behat --profile=custom features/tests.feature
  • DéveloppementConfiguration● Filtres# behat.ymlcustom:...extensions:...filters:tags: "@custom-filter"
  • DéveloppementConfiguration● Filtres@javascript @custom-filterScenario: vérification quun lien est présentGiven I am at "/home"When I hover "Se connecter"Then I wait 1sec for the text "login"
  • Développement● Drupal Extensionhttps://drupal.org/project/drupalextension
  • Développement● Drupal Extension/*** Features context.*/class DrupalContext extends MinkContext implements DrupalAwareInterface {private $drupal, $drupalParameters;/*** Basic auth user and password.*/public $basic_auth;...https://drupal.org/project/drupalextension
  • Développement● Drupal Extension: installation# composer.json{"require": {"drupal/drupal-extension": "*"},"minimum-stability": "dev","config": {"bin-dir": "bin/"}}https://drupal.org/project/drupalextension
  • Développement● Drupal Extension: installtion$ curl http://getcomposer.org/installer | php$ php composer.phar installhttps://drupal.org/project/drupalextension
  • Développement● Drupal Extension: configuration#behat.ymldefault:paths:features: featuresextensions:BehatMinkExtensionExtension:goutte: ~selenium2: ~base_url: http://www.campusfrance.org/https://drupal.org/project/drupalextension
  • Développement● Drupal Extension: configuration#behat.ymldefault:paths:features: featuresextensions:BehatMinkExtensionExtension:goutte: ~selenium2: ~base_url: http://www.campusfrance.org/DrupalDrupalExtensionExtension:blackbox: ~https://drupal.org/project/drupalextension
  • Développement● Drupal Extension en pratiquebin/behat -dl => liste les stepshttps://drupal.org/project/drupalextension
  • Développement● Drupal Extension: user stepsGiven /^I am an anonymous user$/Given /^I am not logged in$/Given /^I am logged in as a user with the "(?P<role>[^"]*)" role$/https://drupal.org/project/drupalextension
  • Développement● Drupal Extension: configuration#behat.ymldefault:paths:features: featuresextensions:...DrupalDrupalExtensionExtension:blackbox: ~drush:alias: myDrushAliashttps://drupal.org/project/drupalextension
  • Opened blackbox● Drupal Extension: user steps# @see Drupal/DrupalExtension/Context/DrupalContext.php/*** Helper function to login the current user.*/public function login() {...$this->getSession()->visit($this->locatePath(/user));$element = $this->getSession()->getPage();$element->fillField($this->getDrupalText(username_field), $this->user->name);$element->fillField($this->getDrupalText(password_field), $this->user->pass);$submit = $element->findButton($this->getDrupalText(log_in));https://drupal.org/project/drupalextension
  • Développement● Drupal Extension: user steps#behat.ymlDrupalDrupalExtensionExtension:text:log_out: "Sign out"log_in: "Sign in"password_field: "Enter your password"username_field: "Nickname"https://drupal.org/project/drupalextension
  • Développement● Drupal Extension: content stepsGiven /^I am viewing (?:a|an) "(?P<type>[^"]*)" node with the title "(?P<title>[^"Given /^I am viewing (?:a|an) "(?P<vocabulary>[^"]*)" term with the name "(?P<name>[^"]*)"$/https://drupal.org/project/drupalextension
  • Développement● Drupal Extension: region stepsThen /^I should see the "(?P<heading>[^"]*)" heading in the "(?P<region>[^"]*)"(?:|regWhen /^I (?:follow|click) "(?P<link>[^"]*)" in the "(?P<region>[^"]*)"(?:| region)$/Then /^I should see the link "(?P<link>[^"]*)" in the "(?P<region>[^"]*)"(?:| region)$/Given /^I press "(?P<button>[^"]*)" in the "(?P<region>[^"]*)"(?:| region)$/https://drupal.org/project/drupalextension
  • Développement● Drupal Extension: region steps#behat.ymlDrupalDrupalExtensionExtension:region_map:My region: "#css-selector"Content: "#main .region-content"Right sidebar: "#sidebar-second"https://drupal.org/project/drupalextension
  • Développement● Drupal Extension: misc stepsGiven /^the cache has been cleared$/Given /^I run cron$/https://drupal.org/project/drupalextension
  • DéveloppementDémo
  • DéveloppementConclusion:Utilisez BDD pour faire des tests de régressions.
  • Introduction aux tests de recette automatisésAvec lextension Drupal pour Behatdidier.boff@ows.frB2F @ drupal.orghttps://github.com/B2Fhttp:///twitter.com/zenelseMerci de votre attention