88
WORKSHOPDAG 27 APRIL 2013 Automatiseren van functionele tests met Behat en Mink &

PFZ Workshop - Automatiseren van functionele tests

Embed Size (px)

Citation preview

WORKSHOPDAG 27 APRIL 2013Automatiseren van functionele tests met Behat en Mink

&

VOORBEREIDING• Download en installeer Virtualbox (https://www.virtualbox.org/)

• Download en installeer Vagrant (http://www.vagrantup.com/)

• https://github.com/pfznl/wsd13-functionaltesting/

• $ git clone https://github.com/pfznl/wsd13-functionaltesting.git

• $ cd wsd13-functionaltesting

• $ vagrant up

• ???

• Profit

WAT HEB JE NODIG?• Computer/laptop

• PHP 5.3

• [Java] (als je selenium wilt draaien)

• Virtualbox

• [Vagrant]

https://github.com/pfznl/wsd13-functionaltesting/

EVEN VOORSTELLEN

• @Richard_Tuin

• Software ontwikkelaar

• Speciale interesse in kwaliteit

• Werkzaam bij Enrise

EN WIE ZIJN JULLIE?

HET PROBLEEM

• Verschillend beeld op scope/werking van de oplevering

• De klant weet soms achteraf pas hoe het systeem precies gebruikt kan worden

• “Het is wel mooi, maar zou x toch y kunnen werken?”

• “Bedankt voor de nieuwe feature, maar nu werkt x niet meer”

HET PROBLEEM

• Verschillend beeld op scope/werking van de oplevering

• De klant weet soms achteraf pas hoe het systeem precies gebruikt kan worden

• “Het is wel mooi, maar zou x toch y kunnen werken?”

• “Bedankt voor de nieuwe feature, maar nu werkt x niet meer”

WANT EIGENLIJK...

• ... hebben we een gezamenlijk doel

• ... willen we wat we gaan bouwen zo nauwkeurig mogelijk definiëren

• ... willen we constante kwaliteit leveren

MAAR ER IS NOG EEN PROBLEEM...

Developers zijn lui

DAT BETEKENT DAT...

• ... we beter, en op gelijk niveau moeten communiceren

• ... we een documentatiesysteem moeten bedenken voor de afstemming

• ... we regelmatig moeten valideren dat wat we leveren nog volgens specificaties is

DAT BETEKENT DAT...

• ... we beter, en op gelijk niveau moeten communiceren

• ... we een documentatiesysteem moeten bedenken voor de afstemming

• ... we regelmatig moeten valideren dat wat we leveren nog volgens specificaties is

Automatiseren?

SAMENWERKEN & DOCUMENTEREN

REGELMATIG (HER)VALIDEREN VAN ACCEPTATIECRITERIA

Documentatie

LATEN WE BIJ HET BEGIN BEGINNEN...(dus nog even geen code)

KWALITEITWat is dat nou eigenlijk?

KWALITEIT=

SOFTWARE DIE AAN DE EISEN VOLDOET

HOE ZORG JE DAN VOOR KWALITEIT?

SAMENWERKEN & DOCUMENTEREN

ITERATIEFis het sleutelwoord

ITERATIEF“Stapsgewijs naar een optimum gaan.”

SOFTWAREONTWIKKELING

AGILE MANIFESTO

Mensen en hun onderlinge interactie > processen and tools

Werkende software > allesomvattende documentatie

Samenwerking met de klant > contractonderhandelingen

Inspelen op verandering > het volgen van een plan

SAMENWERKEN EN DOCUMENTEREN

SAMENWERKEN EN DOCUMENTEREN

1

SAMENWERKEN EN DOCUMENTEREN

1

2

SAMENWERKEN EN DOCUMENTEREN

1

2

3

OPSTELLEN VAN REQUIREMENTS

• Omschrijven hoe een probleem opgelost wordt

• Gezamenlijk met de klant opstellen

• In de taal (technische) van de klant

• Functioneel gericht, niet technisch gericht

Ik wil graag een zoekmachine bouwen, zodat mijn bezoekers het hele internet kunnen

doorzoeken!

Ik wil graag een zoekmachine bouwen, zodat mijn bezoekers het hele internet kunnen

doorzoeken!

Wow, leuke klus!Ik ga direct aan de slag

Alstublieft! Hier is de zoekmachine, mooi hè?

Alstublieft! Hier is de zoekmachine, mooi hè?

Jawel, mooie foto op de achtergrond. En het zoeken werkt, maar ik bedoelde ook dat bezoekers op afbeeldingen kunnen

zoeken!

Alstublieft! Hier is de zoekmachine, mooi hè?

Jawel, mooie foto op de achtergrond. En het zoeken werkt, maar ik bedoelde ook dat bezoekers op afbeeldingen kunnen

zoeken!

Ja zeg, daar kom je nu mee

Alstublieft! Hier is de zoekmachine, mooi hè?

Jawel, mooie foto op de achtergrond. En het zoeken werkt, maar ik bedoelde ook dat bezoekers op afbeeldingen kunnen

zoeken!

Ja zeg, daar kom je nu mee

SCHRIJF VOORBEELDEN!Ter ondersteuning van de communicatie

STAPPENPLAN

1. Omschrijf de feature in één zin

2. Omschrijf de intentie

3. Schrijf realistische scenario’s

PRAKTIJK

Feature: {feature omschrijving}

{intentie}As a {personage(s)}I want {feature}So that {intentie}

Scenario: {scenario omschrijving}Given {context} And {meer context}When {actie}Then {resultaat}

Scenario: ...

Informatie: http://dannorth.net/whats-in-a-story/

VOORBEELD ZOEKFUNCTIEFeature: Search on the internet As a bing.com visitor I want to use the search engine So that i can find information on the internet

Scenario: Simple keyword search Given I am on the homepage When I search the term “PHP” Then I should see search results containing “PHP”

LEVENDE DOCUMENTATIE

• Alle features en scenario’s bij elkaar zijn de documentatie

• Bij een change request werk je deze documentatie daarom bij

OVERWEGINGEN

• Hoe gedetailleerd schrijf je de scenario’s?

• Wie leest/schrijft de scenario’s?

COMMUNICATIE IS DE FOCUSAutomatiseren is maar bijzaak

Developers zijn lui

AUTOMATISERENKun je leren...

“A php framework for testing your business expectations.”

“Mink is an open source acceptance test framework for web applications, written in PHP 5.3.”

+

+

AWESOME

COMPONENTEN VAN EEN FUNCTIONELE TESTSUITE

• Features

• Feature parser

• Browser controller client

• Browser controller/simulator

• Stappen programmeren met browser automatisering

COMPONENTEN VAN EEN FUNCTIONELE TESTSUITE

• Features

• Feature parser

• Browser controller client

• Browser controller/simulator

• Stappen programmeren met browser automatisering

Documentatie

COMPONENTEN VAN EEN FUNCTIONELE TESTSUITE

• Features

• Feature parser

• Browser controller client

• Browser controller/simulator

• Stappen programmeren met browser automatisering

Documentatie

Behat

COMPONENTEN VAN EEN FUNCTIONELE TESTSUITE

• Features

• Feature parser

• Browser controller client

• Browser controller/simulator

• Stappen programmeren met browser automatisering

Documentatie

Behat

Mink

COMPONENTEN VAN EEN FUNCTIONELE TESTSUITE

• Features

• Feature parser

• Browser controller client

• Browser controller/simulator

• Stappen programmeren met browser automatisering

Documentatie

Behat

Mink

Selenium, Sahi, Goutte, etc.

COMPONENTEN VAN EEN FUNCTIONELE TESTSUITE

• Features

• Feature parser

• Browser controller client

• Browser controller/simulator

• Stappen programmeren met browser automatisering

Documentatie

Behat

Mink

Selenium, Sahi, Goutte, etc.

MinkExtension

COMPONENTEN OVERZICHT

TO YOUR BATTLESTATIONS!Tijd voor code

START DE VIRTUALBOX$ vagrant up

Of importeer de OVAOf gebruik je lokale PHP installatie

INSTALLEREN VAN BEHAT1. Maak een map genaamd “testsuite”2. Installeer composer (http://docs.behat.org/quick_intro.html#installation)

3. Maak een bestand composer.json met de volgende inhoud:

4. $ php composer.phar install

{ "require": { "behat/behat": "2.4.*@stable" }, "minimum-stability": "dev", "config": { "bin-dir": "bin/" }}

$ curl http://getcomposer.org/installer | php

INSTALLEREN VAN BEHAT1. Maak een map genaamd “testsuite”2. Installeer composer (http://docs.behat.org/quick_intro.html#installation)

3. Maak een bestand composer.json met de volgende inhoud:

4. $ php composer.phar install

{ "require": { "behat/behat": "2.4.*@stable" }, "minimum-stability": "dev", "config": { "bin-dir": "bin/" }}

That’s it!

$ curl http://getcomposer.org/installer | php

HELLO BEHAT

1. Initialiseer een Behat testsuite met het commando: $ bin/behat --init

2. Behat heeft de volgende mappen en bestanden aangemaakt:

3. Run de testsuite: $ bin/behat

STEPS? (TERMINOLOGIE)

Feature: {feature omschrijving}

{intentie}As a {personage(s)}I want {feature}So that {intentie}

Scenario: {scenario omschrijving}Given {context} And {meer context}When {actie}Then {resultaat}

Scenario: ...

STEPS? (TERMINOLOGIE)

Feature: {feature omschrijving}

{intentie}As a {personage(s)}I want {feature}So that {intentie}

Scenario: {scenario omschrijving}Given {context} And {meer context}When {actie}Then {resultaat}

Scenario: ...

Feature, user story, module

STEPS? (TERMINOLOGIE)

Feature: {feature omschrijving}

{intentie}As a {personage(s)}I want {feature}So that {intentie}

Scenario: {scenario omschrijving}Given {context} And {meer context}When {actie}Then {resultaat}

Scenario: ...

Feature, user story, module

Scenario

STEPS? (TERMINOLOGIE)

Feature: {feature omschrijving}

{intentie}As a {personage(s)}I want {feature}So that {intentie}

Scenario: {scenario omschrijving}Given {context} And {meer context}When {actie}Then {resultaat}

Scenario: ...

Feature, user story, module

Scenario

Steps

VOORBEELD FEATURE

UITBREIDING COMPOSER.JSON{ "require": { "behat/behat": "2.4.*@stable", "behat/mink-extension": "*", "behat/mink": "*", "behat/mink-selenium2-driver": "*", "behat/mink-goutte-driver": "*", "behat/mink-zombie-driver": "*", "behat/mink-sahi-driver": "*" }, "minimum-stability": "dev", "config": { "bin-dir": "bin/" }}

$ composer.phar update

VOORBEELD ZOEKFUNCTIE

Feature: Search on the internet As a bing.com visitor I want to use the search engine So that i can find information on the internet

Scenario: Simple keyword search Given I am on the homepage When I search the term “PHP” Then I should see search results containing “PHP”

features/search.feature

STEP DEFINITIES/** * @Given /^I am on the homepage$/ */public function iAmOnTheHomepage(){ throw new PendingException();}

/** * @When /^I search the term "([^"]*)"$/ */public function iSearchTheTerm($arg1){ throw new PendingException();}

Deze kun je in FeatureContext.php plaatsen, echter...

MINKEXTENSION1. Is een set van (basis) voorgedefinieerde steps

2. Maakt gebruik van Mink

3. Maar... niet alle teksten van de steps zijn even bruikbaar

/** * Opens homepage. * * @Given /^(?:|I )am on (?:|the )homepage$/ * @When /^(?:|I )go to (?:|the )homepage$/ */public function iAmOnHomepage(){ $this->getSession()->visit($this->locatePath('/'));}

MINK TERMINOLOGIE

• Driver = Browser controller/emulator• Session = Browser• Page = Document(Element)

• Element• Selectors

• XPath• CSS• Named

./BEHAT.YMLdefault: extensions: Behat\MinkExtension\Extension: default_session: goutte goutte: ~ base_url: "http://www.bing.com" context: parameters: foo: "bar"

En dan....

$ bin/behat

MINK STEPSGiven /^(?:|I )am on (?:|the )homepage$/When /^(?:|I )go to (?:|the )homepage$/Given /^(?:|I )am on "(?P<page>[^"]+)"$/When /^(?:|I )fill in "(?P<field>(?:[^"]|\\")*)" with "(?P<value>(?:[^"]|\\")*)"$/When /^(?:|I )press "(?P<button>(?:[^"]|\\")*)"$/When /^(?:|I )follow "(?P<link>(?:[^"]|\\")*)"$/Then /^(?:|I )should be on "(?P<page>[^"]+)"$/Then /^(?:|I )should see "(?P<text>(?:[^"]|\\")*)"$/

$ bin/behat -dl

/** * Clicks link with specified id|title|alt|text. * * @When /^(?:|I )follow "(?P<link>(?:[^"]|\\")*)"$/ */public function clickLink($link){ $link = $this->fixStepArgument($link); $this->getSession()->getPage()->clickLink($link);}

FEATURECONTEXT.PHP

• Alles wat je in beginsel nodig hebt

• De class voor je:

• Step definitions

• Hooks

• Initialisatie

STEP DEFINITIES MAKEN/** * @When /^I search the term "([^"]*)"$/ */public function iSearchTheTerm($searchTerm){ $this->fillField('q', $searchTerm); // Mink definities $this->pressButton('go');}

/** * @When /^I search the term "([^"]*)"$/ */public function iSearchTheTerm($searchTerm){ $page = $this->getSession()->getPage(); $page->fillField('q', $searchTerm); $page->pressButton('go');}

UITKOMST

SELECTORS

• Selecteren van elementen

• XPath, CSS, Names$elements = $page->findAll('xpath', './/div[@class="sa_mc"]');$elements = $page->findAll('css', 'div[class="sa_mc"]');$elements = $page->findAll('named', array('link', 'Register');$elements = $page->findAll('named', array('button', 'Search');

DE LAATSTE STAPThen I should see search results containing “PHP”

/** * @Then /^I should see search results containing (.*)$/ */public function iShouldSeeSearchResultsContaining($searchTerm){ $searchTerm = quotemeta($searchTerm); $regex = sprintf('/%s/mi', $searchTerm);

$page = $this->getSession()->getPage(); $elements = $page->findAll('xpath', './/div[@class="sa_mc"]'); foreach ($elements as $element) { if (!preg_match($regex, $element->getText())) { throw new Exception('One of the elements did not match the searchterm'); } }}

PROFIELEN• Volledige configuratie per omgeving

• Selectie op basis van filters

• Te definieren in behat.yml:

• Aan te roepen met: $ bin/behat --profile profielnaam

default: extension: Behat\MinkExtension\Context\MinkContext base_url: “http://www.example.org”profielnaam: extension: Behat\MinkExtension\Context\MinkContext base_url: “http://acc.example.org”

TAGS• Handig om selectie te maken van features/scenario’s

• Via command line: $ bin/behat --tags “@slow”

• Definieer als filters in profile

@smokeFeature: Search on the www@slowScenario: ...

search.feature

slowonly: filters: tags: “@slow”

behat.ymlfast: filters: tags: “~@slow”

behat.yml

FILTERS• Tests groeperen• Snel vs. traag• Tags• Configuratie in behat.ymlsmoketests: filters: tags: “@smoketest&&~@wip”development: filters: tags: “~@slow&&~@wip”

HOOKS

• @beforeSuite

• @beforeFeature

• @beforeScenario

• @beforeStep

• @afterSuite

• @afterFeature

• @afterScenario

• @afterStep

HOOKS/** * @afterScenario */public function logoutUser(){ $this->visit('/logout');}

features/bootstrap/FeatureContext.php

BROWSER CONTROLLERS

Javascript Snelheid Opmerking

Goutte Nee ++ Emulator

Selenium2 Ja -

Sahi Ja ~Geen response

statuscode, headers, authenticatie

Zombie.js Ja +

SCENARIO OUTLINES Scenario Outline: Simple keyword search Given I am on the homepage When I search the term <searchterm> Then I should see search results containing <searchterm>

Examples: | searchterm | | PHP | | Java | | Pie | | This string is possibly too long and uncommon |

DRIVER BENCHMARK

Goutte 2.736ms

Selenium2 16.682ms

Sahi ???

Zombie.js 7.533ms

2007

0 5,000 10,000 15,000 20,000

Goutte Selenium Zombie.js

MULTILINE VARIABLES Scenario: Given I input that spans several lines """ Test one two three """

/** * @Given /^I input that spans several lines$/ */public function iInputThatSpansSeveralLines(PyStringNode $string){ (string) $string; $string->getRaw(); // string $string->getLines(); // array}

TABLES Scenario: Given the following users are registered | name | password | | Foo | test123 | | Admin | secret | When I go to the user overview Then I should see Foo And I should see Admin

/** * @Given /^the following users are registered$/ */public function theFollowingUsersAreRegistered(TableNode $table){ foreach ($table->getHash() as $row) { // ... $row['name'], $row['password'] }}

LET THERE BE TESTING!

BEDANKT

• Feedback: http://joind.in/talk/view/8566

• Vragen?

• @Richard_Tuin

[email protected]

• skype: richardtuin