SlideShare a Scribd company logo
1 of 75
Download to read offline
Test legacy apps
with Behat
Antonis Pavlakis
(@pavlakis)
phpnw15 tutorial day
Long live the legacy
For refactoring, read
this book … >>>
https://leanpub.com/mlaphp
No refactoring needed
(not today)
Today is black-box testing day!
Let’s get started
The environment
• Legacy code - ZF1 (1.10.6) tutorial by Rob Allen
(@akrabat)
• Basic LAMP box with Ubuntu 12.04, PHP 5.5,
MySQL 5.5
Getting started
(1) git clone git@github.com:pavlakis/phpnw15-behat-tutorial.git
(2) vagrant up
(3) Add the following to your hosts file:
192.168.42.200 dev.legacy.com test.legacy.com
setting up Behat
Step 1
composer install
setting up Behat
Create the directory structure.
From inside the /var/www/tests/behat/ folder,
run:
> ../../vendor/bin/behat --init
Step 2
setting up Behat
Create behat.yml
/var/www/tests/behat/behat.yml
Step 3
Step 3default:

suites:

default:

contexts:

- FeatureContext



extensions:



BehatMinkExtension:

browser_name: phantomjs

javascript_session: selenium2

base_url: http://test.legacy.com/



sessions:

my_session:

goutte:

guzzle_parameters:

verify: false



selenium2:

wd_host: "http://localhost:8643/wd/hub"

capabilities: { "browser": "phantomjs" }
Ensure the URL
is accessible from your
server. (e.g. in your hosts
file)
/var/www/tests/behat/behat.yml
Directory
Structure
setting up Behat
Run:
/var/www/vendor/bin/behat --config=/var/www/
tests/behat/behat.yml -f progress
Step 4
Features & Scenarios
Features & Scenarios
Behat tests live inside .feature files
Behat tests are called Scenarios
Behat Scenarios use the Gherkin language, which
allows us to write English statements.
Definitions
A statement from a scenario that maps to a PHP
method and identified through the method’s
doc-block.
For available definitions, run:
$ ./behat --config=/var/www/tests/behat/behat.yml -dl
Enough theory.
Let’s get started with the first test.
“Scenario: The homepage loads”
“Scenario: The homepage loads”
Create file: album.feature
tests/behat/features/bootstrap/album.feature
“Scenario: The homepage loads”
Feature: Albums

I can create, edit and delete albums


Scenario: The homepage loads

Given I am on the homepage

Then I should see text matching "My Album"
tests/behat/features/bootstrap/album.feature
Run the test
Connect to the box: vagrant ssh
Run behat: legacybehat
Exercise #1
“Scenario: Page does not exist”
“Scenario: Page does not exist”
Feature: Albums

I can create, edit and delete albums



Scenario: The homepage loads

Given I am on the homepage

Then I should see text matching "My Album”
Scenario: Page does not exist
Given I …

Then I …
tests/behat/features/bootstrap/album.feature
“Scenario: I can create an album”
“Scenario: I can create an album”
• Possible steps:
• Navigate to the “create” page
• Add artist
• Add album
• Submit form
“Scenario: I can create an album”
Feature: Albums

I can create, edit and delete albums



Scenario: The homepage loads

Given I am on the homepage

Then I should see text matching “My Album”
Scenario: Page does not exist
Given I …

Then I …
Scenario: I can create an album

Given I am on the homepage

And I follow …
tests/behat/features/bootstrap/album.feature
“Scenario: I can create an album”
tests/behat/features/bootstrap/album.feature
Guidance.
Use the following definitions:
And /^(?:|I )follow "(?P<link>(?:[^"]|")*)"$/
And /^(?:|I )fill in "(?P<field>(?:[^"]|")*)" with "(?P<value>(?:[^"]|")*)"$/
And /^(?:|I )press "(?P<button>(?:[^"]|")*)"$/
Exercise #3
“Scenario: I can delete an album”
Exercise #4
“Scenario: I can edit an album”
“A solution…”
Feature: Albums

I can create, edit and delete albums



Scenario: The homepage loads

Given I am on the homepage

Then I should see text matching "My Album"



Scenario: Page does not exist

Given I am on "/notexist"

Then I should see text matching "Page not found"



Scenario: Can create an album

Given I am on the homepage

And I follow "Add new album"

And I fill in "artist" with "Queen"

And I fill in "title" with “A kind of magic"

And I press "Add"

Then I should see text matching "A kind of magic"

And I should be on the homepage



Scenario: Can edit an album

Given I am on the homepage

And I follow "Edit"

And I fill in "artist" with “Billy Joel"

And I fill in "title" with “An Innocent Man"

And I press "Save"

Then I should see text matching “An Innocent Man"

And I should be on the homepage
tests/behat/features/bootstrap/album.feature
Contexts
Contexts
A PHP file that tells Behat how to run our tests.
“Can create a default album”




Scenario: Can create a default album

Given I am on the add page





tests/behat/features/bootstrap/album.feature
Not part of the available definitions
list!
Custom step
$ legacybehat
..................U------
5 scenarios (4 passed, 1 undefined)
25 steps (18 passed, 1 undefined, 6 skipped)
0m0.28s (14.25Mb)
--- FeatureContext has missing steps. Define them with these
snippets:
/**
* @Given I am on the add page
*/
public function iAmOnTheAddPage()
{
throw new PendingException();
}
terminal
Custom step definition
/**

* @Given I am on the add page

*/

public function iAmOnTheAddPage()

{

throw new PendingException();

}

tests/behat/features/bootstrap/FeatureContext.php
Custom step definition
/**

* @Given I am on the add page

*/

public function iAmOnTheAddPage()

{

$this->visit('/index/add');

}
tests/behat/features/bootstrap/FeatureContext.php
First iteration
Scenario: Can create a default album

Given I am on the add page

And I fill in "artist" with "test123"

And I fill in "title" with "test321"

And I press "Add"

Then I should see text matching "test123"

And I should be on the homepage
tests/behat/features/bootstrap/FeatureContext.php
Exercise #5
Making the story more readable
Second iteration
Scenario: Can create a default album

Given I am on the add page

And I create a default album

Then The album has been created
tests/behat/features/bootstrap/FeatureContext.php
Exercise #6
Guidance.
Use the following methods:
$this->fillField($field, $value);
$this->pressButton($button);
$this->assertPageContainsText($text);
tests/behat/features/bootstrap/FeatureContext.php
Traversing Elements
Making sure you’re accessing the
element you want.
(Following, are examples from the http://mink.behat.org/ docs)
Selectors
css selector
Using CSS expressions to search the DOM
$title = $page->find('css', 'h1');
$buttonIcon = $page->find('css', '.btn > .icon');
Selectors
xpath selector
Using path queries to search the DOM
$anchorsWithoutUrl = $page->findAll('xpath', '//
a[not(@href)]');
Exercise #7
Using the CSS selector
(1) Edit a specific album
(2) Delete a specific album
A starting point
$page = $this->getMink()->getSession()->getPage();
tests/behat/features/bootstrap/FeatureContext.php
Can edit a specific album
/**

* @Given I go to edit album by title :title

*/

public function iGoToEditAlbumByTitle($title)

{

$page = $this->getMink()->getSession()->getPage();



$editLink = $page->find(…);



$this->visit($editLink);

}
tests/behat/features/bootstrap/FeatureContext.php
Can edit a specific album
/**

* @Given I go to edit album by title :title

*/

public function iGoToEditAlbumByTitle($title)

{

$page = $this->getMink()->getSession()->getPage();



$editLink = $page->find(

'css',

sprintf('table tr td:contains("%s")', $title)

)

->getParent()

->findLink('Edit')

->getAttribute('href');



$this->visit($editLink);

}
tests/behat/features/bootstrap/FeatureContext.php
Hooks
Hooks
From docs.behat.org
“Behat provides a number of hook points which
allow us to run arbitrary logic at various points in the
Behat test cycle.”
Before Feature
Run some logic before we start running the scenarios.
Before Feature
use BehatBehatHookScopeBeforeFeatureScope;
…
/** @BeforeFeature */

public static function prepareForTheFeature(BeforeFeatureScope $scope)

{



}
tests/behat/features/bootstrap/FeatureContext.php
Clean DB
use BehatBehatHookScopeBeforeFeatureScope;
…
/** @BeforeFeature */

public static function cleanDB(BeforeFeatureScope $scope)

{



}
tests/behat/features/bootstrap/FeatureContext.php
Testing legacy apps?
Roll up your sleeves…
Clean DB #1
use BehatBehatHookScopeBeforeFeatureScope;
…
/** @BeforeFeature */

public static function cleanDB(BeforeFeatureScope $scope)

{



// prepare system for the feature

$username = 'root';

$password = 'Admin123';

$database = 'zf-tutorial-test';

shell_exec("sh /var/www/scripts/db.sh clean {$username} {$password} {$database}");

}
tests/behat/features/bootstrap/FeatureContext.php
No need to hardcode the credentials.
default:

suites:

default:

contexts:

- FeatureContext:

- root

- Admin123

- zf-tutorial-test



extensions:



BehatMinkExtension:

browser_name: phantomjs

javascript_session: selenium2

base_url: http://test.legacy.com/



sessions:

my_session:

goutte:

guzzle_parameters:

verify: false



selenium2:

wd_host: "http://localhost:8643/wd/hub"

capabilities: { "browser": "phantomjs" }
/var/www/tests/behat/behat.yml
/var/www/tests/behat/
features/bootstrap/
FeatureContext.php
Context Parameters
…
public function __construct($username, $password, $dbName)

{

}
…
tests/behat/features/bootstrap/FeatureContext.php
Clean DB #2
use BehatBehatHookScopeBeforeFeatureScope;
…
/** @BeforeFeature */

public static function cleanDB(BeforeFeatureScope $scope)

{



// prepare system for the feature

$dbCreds = $scope->getSuite()->getSetting("contexts")[0]["FeatureContext"];



shell_exec("sh /var/www/scripts/db.sh clean {$dbCreds[0]} {$dbCreds[1]} {$dbCreds[2]}");

}
tests/behat/features/bootstrap/FeatureContext.php
Available Hooks
BeforeSuite
[BehatTestworkHookScopeBeforeSuiteScope]
AfterSuite
[BehatTestworkHookScopeAfterSuiteScope]
BeforeFeature
[BehatBehatHookScopeBeforeFeatureScope]
AfterFeature
[BehatBehatHookScopeAfterFeatureScope]
BeforeScenario
[BehatBehatHookScopeBeforeScenarioScope]
AfterScenario
[BehatBehatHookScopeAfterScenarioScope]
BeforeStep
[BehatBehatHookScopeBeforeStepScope]
AfterStep
[BehatBehatHookScopeAfterStepScope]
Exercise #8
(1) Create a @BeforeFeature to populate
with test data (fixtures/seeders)
(2) Create an @AfterFeature to clean DB
Exercise #9
(1) Create a PDO object
(2) Create an album. Use PDO to
verify it exists in the DB
Connect to DB
public function __construct($username, $password, $dbName)

{

$this->db = new PDO("mysql:host=127.0.0.1;dbname={$dbName}", $username, $password);

}
tests/behat/features/bootstrap/FeatureContext.php
Exercise #10
(1) Create 10 albums through the UI
(2) Verify they exist in the DB
Exercise #11
(1) Create 10 albums through the UI
(2) Delete 5 albums.
(3) Verify they have been deleted in
the DB.
Tags
Tags
“Tags are a great way to organise your features and
scenarios”
- docs.behat.org
Tags
default:

suites:

default:

contexts:

- FeatureContext:

- root

- Admin123

- zf-tutorial-test

filters:

tags: @db
/var/www/tests/behat/behat.yml
Add more using a
comma-separated format.
Tags - Features and Scenarios
@db
Feature: Albums

I can create, edit and delete albums



Scenario: Can create an album

Given I am on the homepage

And I follow "Add new album"

And I fill in "artist" with "Queen"

And I fill in "title" with “A kind of magic"

And I press "Add"

Then I should see text matching "A kind of magic"

And I should be on the homepage

@db

Scenario: Can edit an album

Given I am on the homepage

And I follow "Edit"

And I fill in "artist" with “Billy Joel"

And I fill in "title" with “An Innocent Man"

And I press "Save"

Then I should see text matching “An Innocent Man"

And I should be on the homepage
tests/behat/features/bootstrap/album.feature
Exercise #12
(1) Create a tag with a fixture to
populate DB with a default album.
(2) Create a scenario that edits the
above album.
“A Solution…”
default:

suites:

default:

contexts:

- FeatureContext:

- root

- Admin123

- zf-tutorial-test

filters:

tags: @defaultAlbumFixture,@db
/var/www/tests/behat/behat.yml
“A Solution…”
@db
Feature: Albums

I can create, edit and delete albums



Scenario: Can create an album

Given I am on the homepage

And I follow "Add new album"

And I fill in "artist" with "Queen"

And I fill in "title" with “A kind of magic"

And I press "Add"

Then I should see text matching "A kind of magic"

And I should be on the homepage

@defaultAlbumFixture

Scenario: Can edit an album

Given I am on the homepage

And I follow "Edit"

And I fill in "artist" with “Billy Joel"

And I fill in "title" with “An Innocent Man"

And I press "Save"

Then I should see text matching “An Innocent Man"

And I should be on the homepage
tests/behat/features/bootstrap/album.feature
“A Solution…”
/**

* @BeforeScenario @defaultAlbumFixture

*/

public static function populateDB(BeforeScenarioScope $scope)

{

$dbCreds = $scope->getSuite()->getSetting("contexts")[0]["FeatureContext"];



shell_exec("sh /var/www/scripts/db.sh populate {$dbCreds[0]} {$dbCreds[1]} {$dbCreds[2]}");

}



/**

* @BeforeFeature @db

*/

public static function cleanDB(BeforeFeatureScope $scope)

{

$dbCreds = $scope->getSuite()->getSetting("contexts")[0]["FeatureContext"];





shell_exec("sh /var/www/scripts/db.sh clean {$dbCreds[0]} {$dbCreds[1]} {$dbCreds[2]}");

}
tests/behat/features/bootstrap/FeatureContext.php
Credits
• Rob Allen’s (@akrabat) ZF1 tutorial (http://akrabat.com/zend-
framework-tutorial/ )
• Behat step definitions: http://docs.behat.org/en/v3.0/guides/
2.definitions.html
• Behat contexts: http://docs.behat.org/en/v3.0/guides/
4.contexts.html
• Traversing elements: http://mink.behat.org/en/latest/guides/
traversing-pages.html
• Behat hooks: http://docs.behat.org/en/v3.0/guides/3.hooks.html
Thanks
Antonis Pavlakis
@pavlakis
https://joind.in/talk/view/15420
https://github.com/pavlakis/phpnw15-behat-tutorial

More Related Content

What's hot

Unix shell scripting basics
Unix shell scripting basicsUnix shell scripting basics
Unix shell scripting basics
Abhay Sapru
 
My Robot Poops - In JavaScript (with web sockets)
My Robot Poops - In JavaScript (with web sockets)My Robot Poops - In JavaScript (with web sockets)
My Robot Poops - In JavaScript (with web sockets)
Matthew Schiffman
 

What's hot (10)

Swift Summit 2017: Server Swift State of the Union
Swift Summit 2017: Server Swift State of the UnionSwift Summit 2017: Server Swift State of the Union
Swift Summit 2017: Server Swift State of the Union
 
Unix shell scripting basics
Unix shell scripting basicsUnix shell scripting basics
Unix shell scripting basics
 
has("builds")
has("builds")has("builds")
has("builds")
 
IBM Connection - customize it, #dd13
IBM Connection - customize it, #dd13IBM Connection - customize it, #dd13
IBM Connection - customize it, #dd13
 
Assetic (OSCON)
Assetic (OSCON)Assetic (OSCON)
Assetic (OSCON)
 
Writing Apps the Google-y Way
Writing Apps the Google-y WayWriting Apps the Google-y Way
Writing Apps the Google-y Way
 
Php introduction
Php introductionPhp introduction
Php introduction
 
My Robot Poops - In JavaScript (with web sockets)
My Robot Poops - In JavaScript (with web sockets)My Robot Poops - In JavaScript (with web sockets)
My Robot Poops - In JavaScript (with web sockets)
 
Palm Developer Day PhoneGap
Palm Developer Day PhoneGap Palm Developer Day PhoneGap
Palm Developer Day PhoneGap
 
Machine learning on source code
Machine learning on source codeMachine learning on source code
Machine learning on source code
 

Viewers also liked

Nikol Ježková - Testování v Behatu
Nikol Ježková - Testování v BehatuNikol Ježková - Testování v Behatu
Nikol Ježková - Testování v Behatu
Develcz
 
Behat в PHP с использованием Behat и Mink
Behat в PHP с использованием Behat и MinkBehat в PHP с использованием Behat и Mink
Behat в PHP с использованием Behat и Mink
tyomo4ka
 

Viewers also liked (15)

Being effective with legacy projects
Being effective with legacy projectsBeing effective with legacy projects
Being effective with legacy projects
 
Modern Agile Project Toolbox
Modern Agile Project ToolboxModern Agile Project Toolbox
Modern Agile Project Toolbox
 
BDD в PHP с Behat и Mink
BDD в PHP с Behat и MinkBDD в PHP с Behat и Mink
BDD в PHP с Behat и Mink
 
BDD для PHP проектов
BDD для PHP проектовBDD для PHP проектов
BDD для PHP проектов
 
BDD with Behat Selenium, Sahi and Sauce
BDD with Behat Selenium, Sahi and SauceBDD with Behat Selenium, Sahi and Sauce
BDD with Behat Selenium, Sahi and Sauce
 
Double Loop
Double LoopDouble Loop
Double Loop
 
BDD in PHP - Behat
BDD in PHP - BehatBDD in PHP - Behat
BDD in PHP - Behat
 
BDD with Behat
BDD with BehatBDD with Behat
BDD with Behat
 
Behat - Beyond the Basics (2016 - SunshinePHP)
Behat - Beyond the Basics (2016 - SunshinePHP)Behat - Beyond the Basics (2016 - SunshinePHP)
Behat - Beyond the Basics (2016 - SunshinePHP)
 
Collocation in Distributed Scrum Teams - Lessons Learned
Collocation in Distributed Scrum Teams - Lessons LearnedCollocation in Distributed Scrum Teams - Lessons Learned
Collocation in Distributed Scrum Teams - Lessons Learned
 
Nikol Ježková - Testování v Behatu
Nikol Ježková - Testování v BehatuNikol Ježková - Testování v Behatu
Nikol Ježková - Testování v Behatu
 
Behat в PHP с использованием Behat и Mink
Behat в PHP с использованием Behat и MinkBehat в PHP с использованием Behat и Mink
Behat в PHP с использованием Behat и Mink
 
The concept of Behavior-Driven Development
The concept of Behavior-Driven DevelopmentThe concept of Behavior-Driven Development
The concept of Behavior-Driven Development
 
Web Acceptance Testing with Behat
Web Acceptance Testing with BehatWeb Acceptance Testing with Behat
Web Acceptance Testing with Behat
 
Behat-trick: как мы внедряли BDD на наших проектах
Behat-trick: как мы внедряли BDD на наших проектахBehat-trick: как мы внедряли BDD на наших проектах
Behat-trick: как мы внедряли BDD на наших проектах
 

Similar to Test legacy apps with Behat

UPenn on Rails pt 2
UPenn on Rails pt 2UPenn on Rails pt 2
UPenn on Rails pt 2
Mat Schaffer
 
wwc start-launched
wwc start-launchedwwc start-launched
wwc start-launched
Mat Schaffer
 
Rails 3: Dashing to the Finish
Rails 3: Dashing to the FinishRails 3: Dashing to the Finish
Rails 3: Dashing to the Finish
Yehuda Katz
 
Introducing Assetic (NYPHP)
Introducing Assetic (NYPHP)Introducing Assetic (NYPHP)
Introducing Assetic (NYPHP)
Kris Wallsmith
 
Unix Shell Scripting Basics
Unix Shell Scripting BasicsUnix Shell Scripting Basics
Unix Shell Scripting Basics
Sudharsan S
 
PTW Rails Bootcamp
PTW Rails BootcampPTW Rails Bootcamp
PTW Rails Bootcamp
Mat Schaffer
 

Similar to Test legacy apps with Behat (20)

Sprockets
SprocketsSprockets
Sprockets
 
Creating and Deploying Static Sites with Hugo
Creating and Deploying Static Sites with HugoCreating and Deploying Static Sites with Hugo
Creating and Deploying Static Sites with Hugo
 
UPenn on Rails pt 2
UPenn on Rails pt 2UPenn on Rails pt 2
UPenn on Rails pt 2
 
wwc start-launched
wwc start-launchedwwc start-launched
wwc start-launched
 
Web Scraping
Web ScrapingWeb Scraping
Web Scraping
 
Unix shell scripting basics
Unix shell scripting basicsUnix shell scripting basics
Unix shell scripting basics
 
Rails 3: Dashing to the Finish
Rails 3: Dashing to the FinishRails 3: Dashing to the Finish
Rails 3: Dashing to the Finish
 
Cucumber testing
Cucumber testingCucumber testing
Cucumber testing
 
Cucumber testing
Cucumber testingCucumber testing
Cucumber testing
 
Demystifying Maven
Demystifying MavenDemystifying Maven
Demystifying Maven
 
Backbone the Good Parts
Backbone the Good PartsBackbone the Good Parts
Backbone the Good Parts
 
Introducing Assetic (NYPHP)
Introducing Assetic (NYPHP)Introducing Assetic (NYPHP)
Introducing Assetic (NYPHP)
 
Unix Shell Scripting Basics
Unix Shell Scripting BasicsUnix Shell Scripting Basics
Unix Shell Scripting Basics
 
CPANTS: Kwalitative website and its tools
CPANTS: Kwalitative website and its toolsCPANTS: Kwalitative website and its tools
CPANTS: Kwalitative website and its tools
 
Installing And Configuration for your Wordpress blog
Installing And Configuration for your Wordpress blogInstalling And Configuration for your Wordpress blog
Installing And Configuration for your Wordpress blog
 
Assetic (Symfony Live Paris)
Assetic (Symfony Live Paris)Assetic (Symfony Live Paris)
Assetic (Symfony Live Paris)
 
PTW Rails Bootcamp
PTW Rails BootcampPTW Rails Bootcamp
PTW Rails Bootcamp
 
BASH Variables Part 1: Basic Interpolation
BASH Variables Part 1: Basic InterpolationBASH Variables Part 1: Basic Interpolation
BASH Variables Part 1: Basic Interpolation
 
Introducing Assetic: Asset Management for PHP 5.3
Introducing Assetic: Asset Management for PHP 5.3Introducing Assetic: Asset Management for PHP 5.3
Introducing Assetic: Asset Management for PHP 5.3
 
Zend Lab
Zend LabZend Lab
Zend Lab
 

Recently uploaded

Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...
Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...
Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...
Medical / Health Care (+971588192166) Mifepristone and Misoprostol tablets 200mg
 

Recently uploaded (20)

WSO2Con2024 - GitOps in Action: Navigating Application Deployment in the Plat...
WSO2Con2024 - GitOps in Action: Navigating Application Deployment in the Plat...WSO2Con2024 - GitOps in Action: Navigating Application Deployment in the Plat...
WSO2Con2024 - GitOps in Action: Navigating Application Deployment in the Plat...
 
WSO2CON 2024 Slides - Open Source to SaaS
WSO2CON 2024 Slides - Open Source to SaaSWSO2CON 2024 Slides - Open Source to SaaS
WSO2CON 2024 Slides - Open Source to SaaS
 
AzureNativeQumulo_HPC_Cloud_Native_Benchmarks.pdf
AzureNativeQumulo_HPC_Cloud_Native_Benchmarks.pdfAzureNativeQumulo_HPC_Cloud_Native_Benchmarks.pdf
AzureNativeQumulo_HPC_Cloud_Native_Benchmarks.pdf
 
WSO2CON 2024 Slides - Unlocking Value with AI
WSO2CON 2024 Slides - Unlocking Value with AIWSO2CON 2024 Slides - Unlocking Value with AI
WSO2CON 2024 Slides - Unlocking Value with AI
 
WSO2CON 2024 - Lessons from the Field: Legacy Platforms – It's Time to Let Go...
WSO2CON 2024 - Lessons from the Field: Legacy Platforms – It's Time to Let Go...WSO2CON 2024 - Lessons from the Field: Legacy Platforms – It's Time to Let Go...
WSO2CON 2024 - Lessons from the Field: Legacy Platforms – It's Time to Let Go...
 
Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...
Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...
Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...
 
WSO2CON 2024 - Does Open Source Still Matter?
WSO2CON 2024 - Does Open Source Still Matter?WSO2CON 2024 - Does Open Source Still Matter?
WSO2CON 2024 - Does Open Source Still Matter?
 
WSO2CON 2024 - How to Run a Security Program
WSO2CON 2024 - How to Run a Security ProgramWSO2CON 2024 - How to Run a Security Program
WSO2CON 2024 - How to Run a Security Program
 
WSO2CON 2024 - Freedom First—Unleashing Developer Potential with Open Source
WSO2CON 2024 - Freedom First—Unleashing Developer Potential with Open SourceWSO2CON 2024 - Freedom First—Unleashing Developer Potential with Open Source
WSO2CON 2024 - Freedom First—Unleashing Developer Potential with Open Source
 
WSO2Con2024 - Hello Choreo Presentation - Kanchana
WSO2Con2024 - Hello Choreo Presentation - KanchanaWSO2Con2024 - Hello Choreo Presentation - Kanchana
WSO2Con2024 - Hello Choreo Presentation - Kanchana
 
WSO2CON 2024 - Architecting AI in the Enterprise: APIs and Applications
WSO2CON 2024 - Architecting AI in the Enterprise: APIs and ApplicationsWSO2CON 2024 - Architecting AI in the Enterprise: APIs and Applications
WSO2CON 2024 - Architecting AI in the Enterprise: APIs and Applications
 
WSO2CON 2024 - Building a Digital Government in Uganda
WSO2CON 2024 - Building a Digital Government in UgandaWSO2CON 2024 - Building a Digital Government in Uganda
WSO2CON 2024 - Building a Digital Government in Uganda
 
WSO2Con2024 - WSO2's IAM Vision: Identity-Led Digital Transformation
WSO2Con2024 - WSO2's IAM Vision: Identity-Led Digital TransformationWSO2Con2024 - WSO2's IAM Vision: Identity-Led Digital Transformation
WSO2Con2024 - WSO2's IAM Vision: Identity-Led Digital Transformation
 
WSO2CON2024 - Why Should You Consider Ballerina for Your Next Integration
WSO2CON2024 - Why Should You Consider Ballerina for Your Next IntegrationWSO2CON2024 - Why Should You Consider Ballerina for Your Next Integration
WSO2CON2024 - Why Should You Consider Ballerina for Your Next Integration
 
%in Soweto+277-882-255-28 abortion pills for sale in soweto
%in Soweto+277-882-255-28 abortion pills for sale in soweto%in Soweto+277-882-255-28 abortion pills for sale in soweto
%in Soweto+277-882-255-28 abortion pills for sale in soweto
 
WSO2Con2024 - Organization Management: The Revolution in B2B CIAM
WSO2Con2024 - Organization Management: The Revolution in B2B CIAMWSO2Con2024 - Organization Management: The Revolution in B2B CIAM
WSO2Con2024 - Organization Management: The Revolution in B2B CIAM
 
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
 
WSO2CON2024 - It's time to go Platformless
WSO2CON2024 - It's time to go PlatformlessWSO2CON2024 - It's time to go Platformless
WSO2CON2024 - It's time to go Platformless
 
WSO2Con2024 - Navigating the Digital Landscape: Transforming Healthcare with ...
WSO2Con2024 - Navigating the Digital Landscape: Transforming Healthcare with ...WSO2Con2024 - Navigating the Digital Landscape: Transforming Healthcare with ...
WSO2Con2024 - Navigating the Digital Landscape: Transforming Healthcare with ...
 
WSO2Con204 - Hard Rock Presentation - Keynote
WSO2Con204 - Hard Rock Presentation - KeynoteWSO2Con204 - Hard Rock Presentation - Keynote
WSO2Con204 - Hard Rock Presentation - Keynote
 

Test legacy apps with Behat

  • 1. Test legacy apps with Behat Antonis Pavlakis (@pavlakis) phpnw15 tutorial day
  • 2. Long live the legacy For refactoring, read this book … >>> https://leanpub.com/mlaphp
  • 4. Today is black-box testing day!
  • 6. The environment • Legacy code - ZF1 (1.10.6) tutorial by Rob Allen (@akrabat) • Basic LAMP box with Ubuntu 12.04, PHP 5.5, MySQL 5.5
  • 7. Getting started (1) git clone git@github.com:pavlakis/phpnw15-behat-tutorial.git (2) vagrant up (3) Add the following to your hosts file: 192.168.42.200 dev.legacy.com test.legacy.com
  • 8. setting up Behat Step 1 composer install
  • 9. setting up Behat Create the directory structure. From inside the /var/www/tests/behat/ folder, run: > ../../vendor/bin/behat --init Step 2
  • 10. setting up Behat Create behat.yml /var/www/tests/behat/behat.yml Step 3
  • 11. Step 3default:
 suites:
 default:
 contexts:
 - FeatureContext
 
 extensions:
 
 BehatMinkExtension:
 browser_name: phantomjs
 javascript_session: selenium2
 base_url: http://test.legacy.com/
 
 sessions:
 my_session:
 goutte:
 guzzle_parameters:
 verify: false
 
 selenium2:
 wd_host: "http://localhost:8643/wd/hub"
 capabilities: { "browser": "phantomjs" } Ensure the URL is accessible from your server. (e.g. in your hosts file) /var/www/tests/behat/behat.yml
  • 13. setting up Behat Run: /var/www/vendor/bin/behat --config=/var/www/ tests/behat/behat.yml -f progress Step 4
  • 15. Features & Scenarios Behat tests live inside .feature files Behat tests are called Scenarios Behat Scenarios use the Gherkin language, which allows us to write English statements.
  • 16. Definitions A statement from a scenario that maps to a PHP method and identified through the method’s doc-block. For available definitions, run: $ ./behat --config=/var/www/tests/behat/behat.yml -dl
  • 17. Enough theory. Let’s get started with the first test.
  • 19. “Scenario: The homepage loads” Create file: album.feature tests/behat/features/bootstrap/album.feature
  • 20. “Scenario: The homepage loads” Feature: Albums
 I can create, edit and delete albums 
 Scenario: The homepage loads
 Given I am on the homepage
 Then I should see text matching "My Album" tests/behat/features/bootstrap/album.feature
  • 21. Run the test Connect to the box: vagrant ssh Run behat: legacybehat
  • 22. Exercise #1 “Scenario: Page does not exist”
  • 23. “Scenario: Page does not exist” Feature: Albums
 I can create, edit and delete albums
 
 Scenario: The homepage loads
 Given I am on the homepage
 Then I should see text matching "My Album” Scenario: Page does not exist Given I …
 Then I … tests/behat/features/bootstrap/album.feature
  • 24. “Scenario: I can create an album”
  • 25. “Scenario: I can create an album” • Possible steps: • Navigate to the “create” page • Add artist • Add album • Submit form
  • 26. “Scenario: I can create an album” Feature: Albums
 I can create, edit and delete albums
 
 Scenario: The homepage loads
 Given I am on the homepage
 Then I should see text matching “My Album” Scenario: Page does not exist Given I …
 Then I … Scenario: I can create an album
 Given I am on the homepage
 And I follow … tests/behat/features/bootstrap/album.feature
  • 27. “Scenario: I can create an album” tests/behat/features/bootstrap/album.feature Guidance. Use the following definitions: And /^(?:|I )follow "(?P<link>(?:[^"]|")*)"$/ And /^(?:|I )fill in "(?P<field>(?:[^"]|")*)" with "(?P<value>(?:[^"]|")*)"$/ And /^(?:|I )press "(?P<button>(?:[^"]|")*)"$/
  • 28. Exercise #3 “Scenario: I can delete an album”
  • 29. Exercise #4 “Scenario: I can edit an album”
  • 30. “A solution…” Feature: Albums
 I can create, edit and delete albums
 
 Scenario: The homepage loads
 Given I am on the homepage
 Then I should see text matching "My Album"
 
 Scenario: Page does not exist
 Given I am on "/notexist"
 Then I should see text matching "Page not found"
 
 Scenario: Can create an album
 Given I am on the homepage
 And I follow "Add new album"
 And I fill in "artist" with "Queen"
 And I fill in "title" with “A kind of magic"
 And I press "Add"
 Then I should see text matching "A kind of magic"
 And I should be on the homepage
 
 Scenario: Can edit an album
 Given I am on the homepage
 And I follow "Edit"
 And I fill in "artist" with “Billy Joel"
 And I fill in "title" with “An Innocent Man"
 And I press "Save"
 Then I should see text matching “An Innocent Man"
 And I should be on the homepage tests/behat/features/bootstrap/album.feature
  • 32. Contexts A PHP file that tells Behat how to run our tests.
  • 33. “Can create a default album” 
 
 Scenario: Can create a default album
 Given I am on the add page
 
 
 tests/behat/features/bootstrap/album.feature
  • 34. Not part of the available definitions list!
  • 35. Custom step $ legacybehat ..................U------ 5 scenarios (4 passed, 1 undefined) 25 steps (18 passed, 1 undefined, 6 skipped) 0m0.28s (14.25Mb) --- FeatureContext has missing steps. Define them with these snippets: /** * @Given I am on the add page */ public function iAmOnTheAddPage() { throw new PendingException(); } terminal
  • 36. Custom step definition /**
 * @Given I am on the add page
 */
 public function iAmOnTheAddPage()
 {
 throw new PendingException();
 }
 tests/behat/features/bootstrap/FeatureContext.php
  • 37. Custom step definition /**
 * @Given I am on the add page
 */
 public function iAmOnTheAddPage()
 {
 $this->visit('/index/add');
 } tests/behat/features/bootstrap/FeatureContext.php
  • 38. First iteration Scenario: Can create a default album
 Given I am on the add page
 And I fill in "artist" with "test123"
 And I fill in "title" with "test321"
 And I press "Add"
 Then I should see text matching "test123"
 And I should be on the homepage tests/behat/features/bootstrap/FeatureContext.php
  • 39. Exercise #5 Making the story more readable
  • 40. Second iteration Scenario: Can create a default album
 Given I am on the add page
 And I create a default album
 Then The album has been created tests/behat/features/bootstrap/FeatureContext.php
  • 41. Exercise #6 Guidance. Use the following methods: $this->fillField($field, $value); $this->pressButton($button); $this->assertPageContainsText($text); tests/behat/features/bootstrap/FeatureContext.php
  • 42. Traversing Elements Making sure you’re accessing the element you want. (Following, are examples from the http://mink.behat.org/ docs)
  • 43. Selectors css selector Using CSS expressions to search the DOM $title = $page->find('css', 'h1'); $buttonIcon = $page->find('css', '.btn > .icon');
  • 44. Selectors xpath selector Using path queries to search the DOM $anchorsWithoutUrl = $page->findAll('xpath', '// a[not(@href)]');
  • 45. Exercise #7 Using the CSS selector (1) Edit a specific album (2) Delete a specific album
  • 46. A starting point $page = $this->getMink()->getSession()->getPage(); tests/behat/features/bootstrap/FeatureContext.php
  • 47. Can edit a specific album /**
 * @Given I go to edit album by title :title
 */
 public function iGoToEditAlbumByTitle($title)
 {
 $page = $this->getMink()->getSession()->getPage();
 
 $editLink = $page->find(…);
 
 $this->visit($editLink);
 } tests/behat/features/bootstrap/FeatureContext.php
  • 48. Can edit a specific album /**
 * @Given I go to edit album by title :title
 */
 public function iGoToEditAlbumByTitle($title)
 {
 $page = $this->getMink()->getSession()->getPage();
 
 $editLink = $page->find(
 'css',
 sprintf('table tr td:contains("%s")', $title)
 )
 ->getParent()
 ->findLink('Edit')
 ->getAttribute('href');
 
 $this->visit($editLink);
 } tests/behat/features/bootstrap/FeatureContext.php
  • 49. Hooks
  • 50. Hooks From docs.behat.org “Behat provides a number of hook points which allow us to run arbitrary logic at various points in the Behat test cycle.”
  • 51. Before Feature Run some logic before we start running the scenarios.
  • 52. Before Feature use BehatBehatHookScopeBeforeFeatureScope; … /** @BeforeFeature */
 public static function prepareForTheFeature(BeforeFeatureScope $scope)
 {
 
 } tests/behat/features/bootstrap/FeatureContext.php
  • 53. Clean DB use BehatBehatHookScopeBeforeFeatureScope; … /** @BeforeFeature */
 public static function cleanDB(BeforeFeatureScope $scope)
 {
 
 } tests/behat/features/bootstrap/FeatureContext.php
  • 54. Testing legacy apps? Roll up your sleeves…
  • 55. Clean DB #1 use BehatBehatHookScopeBeforeFeatureScope; … /** @BeforeFeature */
 public static function cleanDB(BeforeFeatureScope $scope)
 {
 
 // prepare system for the feature
 $username = 'root';
 $password = 'Admin123';
 $database = 'zf-tutorial-test';
 shell_exec("sh /var/www/scripts/db.sh clean {$username} {$password} {$database}");
 } tests/behat/features/bootstrap/FeatureContext.php
  • 56. No need to hardcode the credentials.
  • 57. default:
 suites:
 default:
 contexts:
 - FeatureContext:
 - root
 - Admin123
 - zf-tutorial-test
 
 extensions:
 
 BehatMinkExtension:
 browser_name: phantomjs
 javascript_session: selenium2
 base_url: http://test.legacy.com/
 
 sessions:
 my_session:
 goutte:
 guzzle_parameters:
 verify: false
 
 selenium2:
 wd_host: "http://localhost:8643/wd/hub"
 capabilities: { "browser": "phantomjs" } /var/www/tests/behat/behat.yml /var/www/tests/behat/ features/bootstrap/ FeatureContext.php
  • 58. Context Parameters … public function __construct($username, $password, $dbName)
 {
 } … tests/behat/features/bootstrap/FeatureContext.php
  • 59. Clean DB #2 use BehatBehatHookScopeBeforeFeatureScope; … /** @BeforeFeature */
 public static function cleanDB(BeforeFeatureScope $scope)
 {
 
 // prepare system for the feature
 $dbCreds = $scope->getSuite()->getSetting("contexts")[0]["FeatureContext"];
 
 shell_exec("sh /var/www/scripts/db.sh clean {$dbCreds[0]} {$dbCreds[1]} {$dbCreds[2]}");
 } tests/behat/features/bootstrap/FeatureContext.php
  • 61. Exercise #8 (1) Create a @BeforeFeature to populate with test data (fixtures/seeders) (2) Create an @AfterFeature to clean DB
  • 62. Exercise #9 (1) Create a PDO object (2) Create an album. Use PDO to verify it exists in the DB
  • 63. Connect to DB public function __construct($username, $password, $dbName)
 {
 $this->db = new PDO("mysql:host=127.0.0.1;dbname={$dbName}", $username, $password);
 } tests/behat/features/bootstrap/FeatureContext.php
  • 64. Exercise #10 (1) Create 10 albums through the UI (2) Verify they exist in the DB
  • 65. Exercise #11 (1) Create 10 albums through the UI (2) Delete 5 albums. (3) Verify they have been deleted in the DB.
  • 66. Tags
  • 67. Tags “Tags are a great way to organise your features and scenarios” - docs.behat.org
  • 68. Tags default:
 suites:
 default:
 contexts:
 - FeatureContext:
 - root
 - Admin123
 - zf-tutorial-test
 filters:
 tags: @db /var/www/tests/behat/behat.yml Add more using a comma-separated format.
  • 69. Tags - Features and Scenarios @db Feature: Albums
 I can create, edit and delete albums
 
 Scenario: Can create an album
 Given I am on the homepage
 And I follow "Add new album"
 And I fill in "artist" with "Queen"
 And I fill in "title" with “A kind of magic"
 And I press "Add"
 Then I should see text matching "A kind of magic"
 And I should be on the homepage
 @db
 Scenario: Can edit an album
 Given I am on the homepage
 And I follow "Edit"
 And I fill in "artist" with “Billy Joel"
 And I fill in "title" with “An Innocent Man"
 And I press "Save"
 Then I should see text matching “An Innocent Man"
 And I should be on the homepage tests/behat/features/bootstrap/album.feature
  • 70. Exercise #12 (1) Create a tag with a fixture to populate DB with a default album. (2) Create a scenario that edits the above album.
  • 71. “A Solution…” default:
 suites:
 default:
 contexts:
 - FeatureContext:
 - root
 - Admin123
 - zf-tutorial-test
 filters:
 tags: @defaultAlbumFixture,@db /var/www/tests/behat/behat.yml
  • 72. “A Solution…” @db Feature: Albums
 I can create, edit and delete albums
 
 Scenario: Can create an album
 Given I am on the homepage
 And I follow "Add new album"
 And I fill in "artist" with "Queen"
 And I fill in "title" with “A kind of magic"
 And I press "Add"
 Then I should see text matching "A kind of magic"
 And I should be on the homepage
 @defaultAlbumFixture
 Scenario: Can edit an album
 Given I am on the homepage
 And I follow "Edit"
 And I fill in "artist" with “Billy Joel"
 And I fill in "title" with “An Innocent Man"
 And I press "Save"
 Then I should see text matching “An Innocent Man"
 And I should be on the homepage tests/behat/features/bootstrap/album.feature
  • 73. “A Solution…” /**
 * @BeforeScenario @defaultAlbumFixture
 */
 public static function populateDB(BeforeScenarioScope $scope)
 {
 $dbCreds = $scope->getSuite()->getSetting("contexts")[0]["FeatureContext"];
 
 shell_exec("sh /var/www/scripts/db.sh populate {$dbCreds[0]} {$dbCreds[1]} {$dbCreds[2]}");
 }
 
 /**
 * @BeforeFeature @db
 */
 public static function cleanDB(BeforeFeatureScope $scope)
 {
 $dbCreds = $scope->getSuite()->getSetting("contexts")[0]["FeatureContext"];
 
 
 shell_exec("sh /var/www/scripts/db.sh clean {$dbCreds[0]} {$dbCreds[1]} {$dbCreds[2]}");
 } tests/behat/features/bootstrap/FeatureContext.php
  • 74. Credits • Rob Allen’s (@akrabat) ZF1 tutorial (http://akrabat.com/zend- framework-tutorial/ ) • Behat step definitions: http://docs.behat.org/en/v3.0/guides/ 2.definitions.html • Behat contexts: http://docs.behat.org/en/v3.0/guides/ 4.contexts.html • Traversing elements: http://mink.behat.org/en/latest/guides/ traversing-pages.html • Behat hooks: http://docs.behat.org/en/v3.0/guides/3.hooks.html