SlideShare a Scribd company logo
REFACTORING USING CODECEPTION
$I->CANSEE(‘JEROEN’, ‘#VANDIJK’)
$I->USETWITTER(‘@JRVANDIJK’)
$I->AM(‘PHPBNL’, ‘.BOARD-MEMBER’)
$I->WORK(‘#ENRISE’)
Refactoring using Codeception
NETHERLANDS 
UNITED 
KINGDOM 
BELGIUM 
GERMANY 
AMSTERDAM
NETHERLANDS 
UNITED 
KINGDOM 
BELGIUM 
GERMANY 
AMSTERDAM 
NOT AMSTERDAM
NETHERLANDS 
UNITED 
KINGDOM 
BELGIUM 
GERMANY 
AMERSFOORT
GRAIN WAREHOUSE
REFACTORED
THIS TALK IS NOT…
THIS TALK IS NOT… 
REFACTORING 
DEPENDENCY INJECTION, DECOUPLING, ENCAPSULATION, TESTABLE CODE
WHAT IS CODECEPTION? 
A SIMPLE BDD STYLE TESTING FRAMEWORK 
WHICH IS EASY TO READ, WRITE AND DEBUG
YOU WRITE IN YOUR FAVORITE EDITOR
COMPOSER INSTALL CODECEPTION/CODECEPTION 
VENDOR/BIN/CODECEPT BOOTSTRAP
ACCEPTANCE.SUITE.YML 
class_name: AcceptanceTester 
modules: 
enabled: 
- PhpBrowser 
- AcceptanceHelper 
config: 
PhpBrowser: 
url: 'http://www.zendcon.com/'
PAGE USED FOR TESTING
CODECEPT GENERATE:CEST ACCEPTANCE HOME 
public function seeIfNameExists(AcceptanceTester $I) 
{ 
$I->wantTo('see if conference name exists'); 
$I->amOnPage(‘/'); 
$I->click(‘#rt-logo‘); 
$I->see('zendcon'); 
}
STEPS
CODECEPT GENERATE:STEPOBJECT ACCEPTANCE <NAME> 
GENERATED FILE EXTENDS ACCEPTANCETESTER CLASS
REUSE CODE FOR DIFFERENT TESTS 
class CompareSteps extends AcceptanceTester { 
public function seeIfNameExists() 
{ 
$I = $this; 
$I->amOnPage('/'); 
$I->see('zendcon'); 
} 
} 
class MenuCest { 
public function seeIfNameExistsViaCCStep(CompareSteps $I) 
{ 
$I->seeIfNameExists(); 
} 
}
PAGE OBJECTS
CODECEPT GENERATE:PAGEOBJECT ACCEPTANCE <NAME> 
GENERATED FILE IS JUST A CONTAINER
PAGE OBJECT CONTAINER 
class HomePage 
{ 
public static $URL = '/'; 
… // removed code for slide layout purposes 
public static function of(AcceptanceTester $I) 
{ 
return new static($I); 
} 
public function see($value) 
{ 
$I = $this->acceptanceTester; 
$I->amOnPage(self::$URL); 
$I->see($value); 
} 
}
USE THE OBJECT IN A TEST 
public function seeIfNameExistsViaPageObject() 
{ 
HomePage::of($this)->see('zendcon'); 
}
VERSION COMPARISON
MASTER !== RELEASE/NEXTGEN 
FROM A TECHNICAL PERSPECTIVE
MASTER === RELEASE/NEXTGEN 
FROM A FUNCTIONAL PERSPECTIVE
ATTENTION PLEASE 
LOST OF CODE COMING UP…
OVERRIDE DEFAULT CRAWLER 
public function getHtmlFromContent(InnerBrowser $innerBrowser, $css) 
{ 
$crawler = $this->getCrawler($innerBrowser); 
$selector = CssSelector::toXPath($css); 
$value = $crawler->filterXPath($selector); 
return $value->html(); 
} 
protected function getCrawler(InnerBrowser $innerBrowser) 
{ 
$reflection = new ReflectionClass(get_class($innerBrowser)); 
$property = $reflection->getProperty('crawler'); 
$property->setAccessible(true); 
return $property->getValue($innerBrowser); 
}
CREATE SECOND PHPBROWSER INSTANCE 
protected function getPhpBrowserByPage($page) { 
$phpBrowser = $this->getAlternatePhpBrowser(); 
$phpBrowser->amOnPage($page); 
return $phpBrowser; 
} 
protected function getAlternatePhpBrowser() { 
$config = Configuration::config(); 
$suite = Configuration::suiteSettings('acceptance', $config); 
$options = $suite['modules']['config']['PhpBrowser']; 
$options['url'] = $options['alternate-url']; 
$phpBrowser = new PhpBrowser($options)->_initialize(); 
$this->setProxyInGuzzle($phpBrowser->guzzle); 
return $phpBrowser; 
}
GET HTML OF BOTH VERSIONS 
public function getHtml($page, $path) 
{ 
$I = $this; 
$I->amOnPage($page); 
return $this->getHtmlFromContent( 
$I->fetchModule('PhpBrowser'), $path); 
} 
public function getAlternateHtml($page, $path) 
{ 
return $this->getHtmlFromContent( 
$this->getPhpBrowserByPage($page), $path); 
}
ADDING ALTERNATE URL 
class_name: AcceptanceTester 
modules: 
enabled: 
- PhpBrowser 
- AcceptanceHelper 
config: 
PhpBrowser: 
url: 'http://www.zendcon.com/' 
alternate-url: 'http://zendcon.com'
COMPARING 2 VERSIONS IN 1 RUN 
public function seeSameOnVersions($page, $path, $altPath, $message) 
{ 
$I = $this; 
list($left, $right) = $this->getContentFromVersions( 
$page, $path, $altPath); 
$I->seeEquals($left, $right, $message); 
} 
public function getContentFromVersions($page, $path, $altPath) 
{ 
return array( 
$this->getHtml($page, $path), 
$this->getAlternateHtml($page, $altPath) 
); 
}
TEST PAGE HEADER 
public function seeIfPageHeaderIsIdentical(CompareSteps $I) 
{ 
$I->seeSameOnVersions( 
HomePage::$URL, 
'h2', 
'h2', 
'Homepage header not identical' 
); 
}
TEST SIGNUP FORM 
public function seeIfFormActionIsIdentical(CompareSteps $I) 
{ 
$I->seeSameOnVersions( 
HomePage::$URL, 
'.rsformbox1', 
'.rsformbox1', 
'Homepage signup form not identical' 
); 
}
TEST SIGNUP FORM 
public function seeIfFormActionIsIdentical(CompareSteps $I) 
{ 
$I->seeSameOnVersions( 
HomePage::$URL, 
'.rsformbox1', 
'.rsformbox1', 
'Homepage signup form not identical' 
); 
} 
<div class="rsformbox1 title3"> 
- <form method=“post" id="userForm" action="http://www.zendcon.com/"> 
+ <form method="post" id="userForm" action="http://zendcon.com/">
RUNNING THE TESTS!
EXAMPLES?
USER SPECIFIC SETTINGS
CODECEPTION.YML 
CODECEPTION.DIST.YML 
VS 
CODECEPTION.YML.DIST
TESTING AN API
class_name: ApiTester 
modules: 
enabled: 
- ApiHelper 
- PhpBrowser 
- REST 
config: 
PhpBrowser: 
url: https://api.github.com 
REST: 
url: https://api.github.com
public function testGetGists(ApiTester $I) { 
$I->wantTo('see if we can get the gists listing'); 
$I->haveHttpHeader('Accept', 'application/vnd.github.beta+json'); 
$I->sendGet('/users/weierophinney/gists'); 
$I->seeResponseCodeIs(200); 
$I->seeResponseIsJson(); 
} 
public function testGetGist(ApiTester $I) { 
$I->wantTo('see if we can get a gist'); 
$I->haveHttpHeader('Accept', 'application/vnd.github.beta+json'); 
$I->sendGet('/gists/2c47c9d59f4a5214f0c3'); 
$I->seeResponseCodeIs(200); 
$I->seeResponseIsJson(); 
}
ENVIRONMENTS
/** 
* @env beta 
*/ 
public function testGetOldVersionGist(ApiTester $I) { 
$I->wantTo('see if we can get a gist'); 
$I->haveHttpHeader('Accept', $I->getAcceptHeader()); 
$I->sendGet('/gists/2c47c9d59f4a5214f0c3'); 
$I->seeResponseCodeIs(200); 
$I->seeResponseIsJson(); 
$I->seeResponseContainsJson( 
array('user' => array('login' => ‘weierophinney') 
)); 
}
SPOT THE DIFFERENCE 
/** 
* @env version3 
*/ 
public function testGetOldVersionGist(ApiTester $I) { 
$I->wantTo('see if we can get a gist'); 
$I->haveHttpHeader('Accept', $I->getAcceptHeader()); 
$I->sendGet('/gists/2c47c9d59f4a5214f0c3'); 
$I->seeResponseCodeIs(200); 
$I->seeResponseIsJson(); 
$I->seeResponseContainsJson( 
array('owner' => array('login' => ‘weierophinney') 
)); 
}
SUITE CONFIG ADDITIONS 
env: 
beta: 
config: 
data: 
accept: application/vnd.github.beta+json 
version3: 
config: 
data: 
accept: application/vnd.github.v3+json
CODECEPT RUN API —ENV BETA —ENV VERSION3 
TESTING 2 API VERSION IN 1 RUN
EXAMPLES?
READY TO DIG DEEPER? 
USING MODULES
CODECEPT GENERATE:SUITE 
USE YOUR IMAGINATION
FILESYSTEM MODULE 
class MigrateHelper extends CodeceptionModule { 
public function seeIfLineExistsInFile($file, $line) 
{ 
$filesystem = $this->getModule('Filesystem'); 
$filesystem->seeFileFound($file); 
$filesystem->seeInThisFile($line); 
} 
} 
class HostCest { 
public function testIfHostsFileIsConfigured(MigrateTester $I) 
{ 
$I->seeIfLineExistsInFile('/etc/hosts', '127.0.0.1'); 
} 
}
CLI MODULE 
class MigrateHelper extends CodeceptionModule { 
public function seeIfPortIsReachable($host, $port) 
{ 
$cli = $this->getModule('Cli'); 
$cli->runShellCommand('nmap '.$host.' -Pn -p '.$port); 
$cli->seeInShellOutput($port.'/tcp open'); 
} 
} 
class HostCest { 
public function testIfPortReachable(MigrateTester $I) 
{ 
$I->seeIfPortIsReachable('www.zendcon.com', 80); 
} 
}
CLI MODULE 
class MigrateHelper extends CodeceptionModule { 
public function seeAddressIsMatchingIp($address, $ip) 
{ 
$cli = $this->getModule('Cli'); 
$cli->runShellCommand('host '.$address); 
$cli->seeInShellOutput($address . ' has address '.$ip); 
} 
} 
class HostCest { 
public function testIfDnsCanBeResolved(MigrateTester $I) 
{ 
$I->seeAddressIsMatchingIp('zendcon.com', '50.56.0.87'); 
} 
}
FTP MODULE 
class MigrateHelper extends CodeceptionModule { 
public function seeContentsInRemoteFile($file, $line) 
{ 
$server = $this->getModule('FTP'); 
$server->seeFileFound(basename($file), dirname($file)); 
$server->openFile($file); 
$server->seeInThisFile($line); 
} 
} 
class HostCest { 
public function testIfRemoteFileHasContents(MigrateTester $I) 
{ 
$I->seeContentsInRemoteFile('/etc/hosts', '127.0.0.1'); 
} 
}
CAVEAT! 
FTP MODULE SIGNS IN BEFORE EVERY TEST
RUNNING THE TESTS!
GITHUB.COM/JVANDIJK/ZC14-CODECEPTION 
JOIND.IN/11997
Ad

Recommended

Crafting beautiful software
Crafting beautiful software
Jorn Oomen
 
Symfony2 Building on Alpha / Beta technology
Symfony2 Building on Alpha / Beta technology
Daniel Knell
 
PHPSpec - the only Design Tool you need - 4Developers
PHPSpec - the only Design Tool you need - 4Developers
Kacper Gunia
 
Hacking Your Way To Better Security - Dutch PHP Conference 2016
Hacking Your Way To Better Security - Dutch PHP Conference 2016
Colin O'Dell
 
November Camp - Spec BDD with PHPSpec 2
November Camp - Spec BDD with PHPSpec 2
Kacper Gunia
 
PhpSpec 2.0 ilustrated by examples
PhpSpec 2.0 ilustrated by examples
Marcello Duarte
 
You code sucks, let's fix it
You code sucks, let's fix it
Rafael Dohms
 
Mocking Demystified
Mocking Demystified
Marcello Duarte
 
Forget about Index.php and build you applications around HTTP - PHPers Cracow
Forget about Index.php and build you applications around HTTP - PHPers Cracow
Kacper Gunia
 
Object Calisthenics Applied to PHP
Object Calisthenics Applied to PHP
Guilherme Blanco
 
The IoC Hydra - Dutch PHP Conference 2016
The IoC Hydra - Dutch PHP Conference 2016
Kacper Gunia
 
Learning Perl 6 (NPW 2007)
Learning Perl 6 (NPW 2007)
brian d foy
 
Unit testing with zend framework PHPBenelux
Unit testing with zend framework PHPBenelux
Michelangelo van Dam
 
PHP for Adults: Clean Code and Object Calisthenics
PHP for Adults: Clean Code and Object Calisthenics
Guilherme Blanco
 
Unit testing with zend framework tek11
Unit testing with zend framework tek11
Michelangelo van Dam
 
Forget about index.php and build you applications around HTTP!
Forget about index.php and build you applications around HTTP!
Kacper Gunia
 
Design Patterns avec PHP 5.3, Symfony et Pimple
Design Patterns avec PHP 5.3, Symfony et Pimple
Hugo Hamon
 
Silex meets SOAP & REST
Silex meets SOAP & REST
Hugo Hamon
 
logic321
logic321
logic321
 
Learning Perl 6
Learning Perl 6
brian d foy
 
Database Design Patterns
Database Design Patterns
Hugo Hamon
 
Business Rules with Brick
Business Rules with Brick
brian d foy
 
Data Validation models
Data Validation models
Marcin Czarnecki
 
Symfony2 - extending the console component
Symfony2 - extending the console component
Hugo Hamon
 
The IoC Hydra
The IoC Hydra
Kacper Gunia
 
The History of PHPersistence
The History of PHPersistence
Hugo Hamon
 
Your code sucks, let's fix it
Your code sucks, let's fix it
Rafael Dohms
 
Storytelling By Numbers
Storytelling By Numbers
Michael King
 
The Enterprise Wor/d/thy/Press
The Enterprise Wor/d/thy/Press
Jeroen van Dijk
 
The Enterprise Wor/d/thy/Press
The Enterprise Wor/d/thy/Press
Jeroen van Dijk
 

More Related Content

What's hot (20)

Forget about Index.php and build you applications around HTTP - PHPers Cracow
Forget about Index.php and build you applications around HTTP - PHPers Cracow
Kacper Gunia
 
Object Calisthenics Applied to PHP
Object Calisthenics Applied to PHP
Guilherme Blanco
 
The IoC Hydra - Dutch PHP Conference 2016
The IoC Hydra - Dutch PHP Conference 2016
Kacper Gunia
 
Learning Perl 6 (NPW 2007)
Learning Perl 6 (NPW 2007)
brian d foy
 
Unit testing with zend framework PHPBenelux
Unit testing with zend framework PHPBenelux
Michelangelo van Dam
 
PHP for Adults: Clean Code and Object Calisthenics
PHP for Adults: Clean Code and Object Calisthenics
Guilherme Blanco
 
Unit testing with zend framework tek11
Unit testing with zend framework tek11
Michelangelo van Dam
 
Forget about index.php and build you applications around HTTP!
Forget about index.php and build you applications around HTTP!
Kacper Gunia
 
Design Patterns avec PHP 5.3, Symfony et Pimple
Design Patterns avec PHP 5.3, Symfony et Pimple
Hugo Hamon
 
Silex meets SOAP & REST
Silex meets SOAP & REST
Hugo Hamon
 
logic321
logic321
logic321
 
Learning Perl 6
Learning Perl 6
brian d foy
 
Database Design Patterns
Database Design Patterns
Hugo Hamon
 
Business Rules with Brick
Business Rules with Brick
brian d foy
 
Data Validation models
Data Validation models
Marcin Czarnecki
 
Symfony2 - extending the console component
Symfony2 - extending the console component
Hugo Hamon
 
The IoC Hydra
The IoC Hydra
Kacper Gunia
 
The History of PHPersistence
The History of PHPersistence
Hugo Hamon
 
Your code sucks, let's fix it
Your code sucks, let's fix it
Rafael Dohms
 
Storytelling By Numbers
Storytelling By Numbers
Michael King
 
Forget about Index.php and build you applications around HTTP - PHPers Cracow
Forget about Index.php and build you applications around HTTP - PHPers Cracow
Kacper Gunia
 
Object Calisthenics Applied to PHP
Object Calisthenics Applied to PHP
Guilherme Blanco
 
The IoC Hydra - Dutch PHP Conference 2016
The IoC Hydra - Dutch PHP Conference 2016
Kacper Gunia
 
Learning Perl 6 (NPW 2007)
Learning Perl 6 (NPW 2007)
brian d foy
 
Unit testing with zend framework PHPBenelux
Unit testing with zend framework PHPBenelux
Michelangelo van Dam
 
PHP for Adults: Clean Code and Object Calisthenics
PHP for Adults: Clean Code and Object Calisthenics
Guilherme Blanco
 
Unit testing with zend framework tek11
Unit testing with zend framework tek11
Michelangelo van Dam
 
Forget about index.php and build you applications around HTTP!
Forget about index.php and build you applications around HTTP!
Kacper Gunia
 
Design Patterns avec PHP 5.3, Symfony et Pimple
Design Patterns avec PHP 5.3, Symfony et Pimple
Hugo Hamon
 
Silex meets SOAP & REST
Silex meets SOAP & REST
Hugo Hamon
 
Learning Perl 6
Learning Perl 6
brian d foy
 
Database Design Patterns
Database Design Patterns
Hugo Hamon
 
Business Rules with Brick
Business Rules with Brick
brian d foy
 
Symfony2 - extending the console component
Symfony2 - extending the console component
Hugo Hamon
 
The History of PHPersistence
The History of PHPersistence
Hugo Hamon
 
Your code sucks, let's fix it
Your code sucks, let's fix it
Rafael Dohms
 
Storytelling By Numbers
Storytelling By Numbers
Michael King
 

Viewers also liked (6)

The Enterprise Wor/d/thy/Press
The Enterprise Wor/d/thy/Press
Jeroen van Dijk
 
The Enterprise Wor/d/thy/Press
The Enterprise Wor/d/thy/Press
Jeroen van Dijk
 
WordPress REST API hacking
WordPress REST API hacking
Jeroen van Dijk
 
TDD with PhpSpec
TDD with PhpSpec
CiaranMcNulty
 
WordPress REST API hacking
WordPress REST API hacking
Jeroen van Dijk
 
Faire la conception en équipe sans architecte, non mais allô quoi ?
Faire la conception en équipe sans architecte, non mais allô quoi ?
Ly-Jia Goldstein
 
The Enterprise Wor/d/thy/Press
The Enterprise Wor/d/thy/Press
Jeroen van Dijk
 
The Enterprise Wor/d/thy/Press
The Enterprise Wor/d/thy/Press
Jeroen van Dijk
 
WordPress REST API hacking
WordPress REST API hacking
Jeroen van Dijk
 
WordPress REST API hacking
WordPress REST API hacking
Jeroen van Dijk
 
Faire la conception en équipe sans architecte, non mais allô quoi ?
Faire la conception en équipe sans architecte, non mais allô quoi ?
Ly-Jia Goldstein
 
Ad

Similar to Refactoring using Codeception (20)

Unit testing after Zend Framework 1.8
Unit testing after Zend Framework 1.8
Michelangelo van Dam
 
Unit testing zend framework apps
Unit testing zend framework apps
Michelangelo van Dam
 
Unittests für Dummies
Unittests für Dummies
Lars Jankowfsky
 
Symfony2, creare bundle e valore per il cliente
Symfony2, creare bundle e valore per il cliente
Leonardo Proietti
 
How Kris Writes Symfony Apps
How Kris Writes Symfony Apps
Kris Wallsmith
 
PhpUnit - The most unknown Parts
PhpUnit - The most unknown Parts
Bastian Feder
 
Doctrine For Beginners
Doctrine For Beginners
Jonathan Wage
 
Dutch PHP Conference - PHPSpec 2 - The only Design Tool you need
Dutch PHP Conference - PHPSpec 2 - The only Design Tool you need
Kacper Gunia
 
Php unit the-mostunknownparts
Php unit the-mostunknownparts
Bastian Feder
 
international PHP2011_Bastian Feder_The most unknown Parts of PHPUnit
international PHP2011_Bastian Feder_The most unknown Parts of PHPUnit
smueller_sandsmedia
 
Why is crud a bad idea - focus on real scenarios
Why is crud a bad idea - focus on real scenarios
Divante
 
PHPSpec BDD Framework
PHPSpec BDD Framework
Marcello Duarte
 
Phpne august-2012-symfony-components-friends
Phpne august-2012-symfony-components-friends
Michael Peacock
 
Min-Maxing Software Costs
Min-Maxing Software Costs
Konstantin Kudryashov
 
関西PHP勉強会 php5.4つまみぐい
関西PHP勉強会 php5.4つまみぐい
Hisateru Tanaka
 
SOLID PRINCIPLES
SOLID PRINCIPLES
Luciano Queiroz
 
Symfony tips and tricks
Symfony tips and tricks
Mariusz Kozłowski
 
Symfony components in the wild, PHPNW12
Symfony components in the wild, PHPNW12
Jakub Zalas
 
Php unit the-mostunknownparts
Php unit the-mostunknownparts
Bastian Feder
 
QA for PHP projects
QA for PHP projects
Michelangelo van Dam
 
Unit testing after Zend Framework 1.8
Unit testing after Zend Framework 1.8
Michelangelo van Dam
 
Symfony2, creare bundle e valore per il cliente
Symfony2, creare bundle e valore per il cliente
Leonardo Proietti
 
How Kris Writes Symfony Apps
How Kris Writes Symfony Apps
Kris Wallsmith
 
PhpUnit - The most unknown Parts
PhpUnit - The most unknown Parts
Bastian Feder
 
Doctrine For Beginners
Doctrine For Beginners
Jonathan Wage
 
Dutch PHP Conference - PHPSpec 2 - The only Design Tool you need
Dutch PHP Conference - PHPSpec 2 - The only Design Tool you need
Kacper Gunia
 
Php unit the-mostunknownparts
Php unit the-mostunknownparts
Bastian Feder
 
international PHP2011_Bastian Feder_The most unknown Parts of PHPUnit
international PHP2011_Bastian Feder_The most unknown Parts of PHPUnit
smueller_sandsmedia
 
Why is crud a bad idea - focus on real scenarios
Why is crud a bad idea - focus on real scenarios
Divante
 
Phpne august-2012-symfony-components-friends
Phpne august-2012-symfony-components-friends
Michael Peacock
 
関西PHP勉強会 php5.4つまみぐい
関西PHP勉強会 php5.4つまみぐい
Hisateru Tanaka
 
Symfony components in the wild, PHPNW12
Symfony components in the wild, PHPNW12
Jakub Zalas
 
Php unit the-mostunknownparts
Php unit the-mostunknownparts
Bastian Feder
 
Ad

More from Jeroen van Dijk (12)

Beacons in Appcelerator Titanium
Beacons in Appcelerator Titanium
Jeroen van Dijk
 
Teaming up WordPress API with Backbone.js in Titanium
Teaming up WordPress API with Backbone.js in Titanium
Jeroen van Dijk
 
Teaming up WordPress API with Backbone.js in Titanium
Teaming up WordPress API with Backbone.js in Titanium
Jeroen van Dijk
 
An app on the shoulders of giants
An app on the shoulders of giants
Jeroen van Dijk
 
Zend Server: Not just a PHP stack
Zend Server: Not just a PHP stack
Jeroen van Dijk
 
Liking Relevance - PHP North East 2014
Liking Relevance - PHP North East 2014
Jeroen van Dijk
 
To SQL or No(t)SQL - PHPNW12
To SQL or No(t)SQL - PHPNW12
Jeroen van Dijk
 
To SQL or No(t)SQL - PFCongres 2012
To SQL or No(t)SQL - PFCongres 2012
Jeroen van Dijk
 
Socializing a world of travel
Socializing a world of travel
Jeroen van Dijk
 
Varnish, the high performance valhalla?
Varnish, the high performance valhalla?
Jeroen van Dijk
 
Varnish, the high performance valhalla?
Varnish, the high performance valhalla?
Jeroen van Dijk
 
Edge Side Includes in Zend Framework without Varnish
Edge Side Includes in Zend Framework without Varnish
Jeroen van Dijk
 
Beacons in Appcelerator Titanium
Beacons in Appcelerator Titanium
Jeroen van Dijk
 
Teaming up WordPress API with Backbone.js in Titanium
Teaming up WordPress API with Backbone.js in Titanium
Jeroen van Dijk
 
Teaming up WordPress API with Backbone.js in Titanium
Teaming up WordPress API with Backbone.js in Titanium
Jeroen van Dijk
 
An app on the shoulders of giants
An app on the shoulders of giants
Jeroen van Dijk
 
Zend Server: Not just a PHP stack
Zend Server: Not just a PHP stack
Jeroen van Dijk
 
Liking Relevance - PHP North East 2014
Liking Relevance - PHP North East 2014
Jeroen van Dijk
 
To SQL or No(t)SQL - PHPNW12
To SQL or No(t)SQL - PHPNW12
Jeroen van Dijk
 
To SQL or No(t)SQL - PFCongres 2012
To SQL or No(t)SQL - PFCongres 2012
Jeroen van Dijk
 
Socializing a world of travel
Socializing a world of travel
Jeroen van Dijk
 
Varnish, the high performance valhalla?
Varnish, the high performance valhalla?
Jeroen van Dijk
 
Varnish, the high performance valhalla?
Varnish, the high performance valhalla?
Jeroen van Dijk
 
Edge Side Includes in Zend Framework without Varnish
Edge Side Includes in Zend Framework without Varnish
Jeroen van Dijk
 

Recently uploaded (20)

Cyber Defense Matrix Workshop - RSA Conference
Cyber Defense Matrix Workshop - RSA Conference
Priyanka Aash
 
FIDO Seminar: Authentication for a Billion Consumers - Amazon.pptx
FIDO Seminar: Authentication for a Billion Consumers - Amazon.pptx
FIDO Alliance
 
Wenn alles versagt - IBM Tape schützt, was zählt! Und besonders mit dem neust...
Wenn alles versagt - IBM Tape schützt, was zählt! Und besonders mit dem neust...
Josef Weingand
 
Improving Data Integrity: Synchronization between EAM and ArcGIS Utility Netw...
Improving Data Integrity: Synchronization between EAM and ArcGIS Utility Netw...
Safe Software
 
ReSTIR [DI]: Spatiotemporal reservoir resampling for real-time ray tracing ...
ReSTIR [DI]: Spatiotemporal reservoir resampling for real-time ray tracing ...
revolcs10
 
War_And_Cyber_3_Years_Of_Struggle_And_Lessons_For_Global_Security.pdf
War_And_Cyber_3_Years_Of_Struggle_And_Lessons_For_Global_Security.pdf
biswajitbanerjee38
 
Edge-banding-machines-edgeteq-s-200-en-.pdf
Edge-banding-machines-edgeteq-s-200-en-.pdf
AmirStern2
 
cnc-processing-centers-centateq-p-110-en.pdf
cnc-processing-centers-centateq-p-110-en.pdf
AmirStern2
 
Powering Multi-Page Web Applications Using Flow Apps and FME Data Streaming
Powering Multi-Page Web Applications Using Flow Apps and FME Data Streaming
Safe Software
 
OpenACC and Open Hackathons Monthly Highlights June 2025
OpenACC and Open Hackathons Monthly Highlights June 2025
OpenACC
 
Security Tips for Enterprise Azure Solutions
Security Tips for Enterprise Azure Solutions
Michele Leroux Bustamante
 
Can We Use Rust to Develop Extensions for PostgreSQL? (POSETTE: An Event for ...
Can We Use Rust to Develop Extensions for PostgreSQL? (POSETTE: An Event for ...
NTT DATA Technology & Innovation
 
FIDO Alliance Seminar State of Passkeys.pptx
FIDO Alliance Seminar State of Passkeys.pptx
FIDO Alliance
 
AI VIDEO MAGAZINE - June 2025 - r/aivideo
AI VIDEO MAGAZINE - June 2025 - r/aivideo
1pcity Studios, Inc
 
MuleSoft for AgentForce : Topic Center and API Catalog
MuleSoft for AgentForce : Topic Center and API Catalog
shyamraj55
 
Smarter Aviation Data Management: Lessons from Swedavia Airports and Sweco
Smarter Aviation Data Management: Lessons from Swedavia Airports and Sweco
Safe Software
 
No-Code Workflows for CAD & 3D Data: Scaling AI-Driven Infrastructure
No-Code Workflows for CAD & 3D Data: Scaling AI-Driven Infrastructure
Safe Software
 
"Database isolation: how we deal with hundreds of direct connections to the d...
"Database isolation: how we deal with hundreds of direct connections to the d...
Fwdays
 
PyCon SG 25 - Firecracker Made Easy with Python.pdf
PyCon SG 25 - Firecracker Made Easy with Python.pdf
Muhammad Yuga Nugraha
 
Creating Inclusive Digital Learning with AI: A Smarter, Fairer Future
Creating Inclusive Digital Learning with AI: A Smarter, Fairer Future
Impelsys Inc.
 
Cyber Defense Matrix Workshop - RSA Conference
Cyber Defense Matrix Workshop - RSA Conference
Priyanka Aash
 
FIDO Seminar: Authentication for a Billion Consumers - Amazon.pptx
FIDO Seminar: Authentication for a Billion Consumers - Amazon.pptx
FIDO Alliance
 
Wenn alles versagt - IBM Tape schützt, was zählt! Und besonders mit dem neust...
Wenn alles versagt - IBM Tape schützt, was zählt! Und besonders mit dem neust...
Josef Weingand
 
Improving Data Integrity: Synchronization between EAM and ArcGIS Utility Netw...
Improving Data Integrity: Synchronization between EAM and ArcGIS Utility Netw...
Safe Software
 
ReSTIR [DI]: Spatiotemporal reservoir resampling for real-time ray tracing ...
ReSTIR [DI]: Spatiotemporal reservoir resampling for real-time ray tracing ...
revolcs10
 
War_And_Cyber_3_Years_Of_Struggle_And_Lessons_For_Global_Security.pdf
War_And_Cyber_3_Years_Of_Struggle_And_Lessons_For_Global_Security.pdf
biswajitbanerjee38
 
Edge-banding-machines-edgeteq-s-200-en-.pdf
Edge-banding-machines-edgeteq-s-200-en-.pdf
AmirStern2
 
cnc-processing-centers-centateq-p-110-en.pdf
cnc-processing-centers-centateq-p-110-en.pdf
AmirStern2
 
Powering Multi-Page Web Applications Using Flow Apps and FME Data Streaming
Powering Multi-Page Web Applications Using Flow Apps and FME Data Streaming
Safe Software
 
OpenACC and Open Hackathons Monthly Highlights June 2025
OpenACC and Open Hackathons Monthly Highlights June 2025
OpenACC
 
Security Tips for Enterprise Azure Solutions
Security Tips for Enterprise Azure Solutions
Michele Leroux Bustamante
 
Can We Use Rust to Develop Extensions for PostgreSQL? (POSETTE: An Event for ...
Can We Use Rust to Develop Extensions for PostgreSQL? (POSETTE: An Event for ...
NTT DATA Technology & Innovation
 
FIDO Alliance Seminar State of Passkeys.pptx
FIDO Alliance Seminar State of Passkeys.pptx
FIDO Alliance
 
AI VIDEO MAGAZINE - June 2025 - r/aivideo
AI VIDEO MAGAZINE - June 2025 - r/aivideo
1pcity Studios, Inc
 
MuleSoft for AgentForce : Topic Center and API Catalog
MuleSoft for AgentForce : Topic Center and API Catalog
shyamraj55
 
Smarter Aviation Data Management: Lessons from Swedavia Airports and Sweco
Smarter Aviation Data Management: Lessons from Swedavia Airports and Sweco
Safe Software
 
No-Code Workflows for CAD & 3D Data: Scaling AI-Driven Infrastructure
No-Code Workflows for CAD & 3D Data: Scaling AI-Driven Infrastructure
Safe Software
 
"Database isolation: how we deal with hundreds of direct connections to the d...
"Database isolation: how we deal with hundreds of direct connections to the d...
Fwdays
 
PyCon SG 25 - Firecracker Made Easy with Python.pdf
PyCon SG 25 - Firecracker Made Easy with Python.pdf
Muhammad Yuga Nugraha
 
Creating Inclusive Digital Learning with AI: A Smarter, Fairer Future
Creating Inclusive Digital Learning with AI: A Smarter, Fairer Future
Impelsys Inc.
 

Refactoring using Codeception

  • 7. NETHERLANDS UNITED KINGDOM BELGIUM GERMANY AMSTERDAM
  • 8. NETHERLANDS UNITED KINGDOM BELGIUM GERMANY AMSTERDAM NOT AMSTERDAM
  • 9. NETHERLANDS UNITED KINGDOM BELGIUM GERMANY AMERSFOORT
  • 12. THIS TALK IS NOT…
  • 13. THIS TALK IS NOT… REFACTORING DEPENDENCY INJECTION, DECOUPLING, ENCAPSULATION, TESTABLE CODE
  • 14. WHAT IS CODECEPTION? A SIMPLE BDD STYLE TESTING FRAMEWORK WHICH IS EASY TO READ, WRITE AND DEBUG
  • 15. YOU WRITE IN YOUR FAVORITE EDITOR
  • 16. COMPOSER INSTALL CODECEPTION/CODECEPTION VENDOR/BIN/CODECEPT BOOTSTRAP
  • 17. ACCEPTANCE.SUITE.YML class_name: AcceptanceTester modules: enabled: - PhpBrowser - AcceptanceHelper config: PhpBrowser: url: 'http://www.zendcon.com/'
  • 18. PAGE USED FOR TESTING
  • 19. CODECEPT GENERATE:CEST ACCEPTANCE HOME public function seeIfNameExists(AcceptanceTester $I) { $I->wantTo('see if conference name exists'); $I->amOnPage(‘/'); $I->click(‘#rt-logo‘); $I->see('zendcon'); }
  • 20. STEPS
  • 21. CODECEPT GENERATE:STEPOBJECT ACCEPTANCE <NAME> GENERATED FILE EXTENDS ACCEPTANCETESTER CLASS
  • 22. REUSE CODE FOR DIFFERENT TESTS class CompareSteps extends AcceptanceTester { public function seeIfNameExists() { $I = $this; $I->amOnPage('/'); $I->see('zendcon'); } } class MenuCest { public function seeIfNameExistsViaCCStep(CompareSteps $I) { $I->seeIfNameExists(); } }
  • 24. CODECEPT GENERATE:PAGEOBJECT ACCEPTANCE <NAME> GENERATED FILE IS JUST A CONTAINER
  • 25. PAGE OBJECT CONTAINER class HomePage { public static $URL = '/'; … // removed code for slide layout purposes public static function of(AcceptanceTester $I) { return new static($I); } public function see($value) { $I = $this->acceptanceTester; $I->amOnPage(self::$URL); $I->see($value); } }
  • 26. USE THE OBJECT IN A TEST public function seeIfNameExistsViaPageObject() { HomePage::of($this)->see('zendcon'); }
  • 28. MASTER !== RELEASE/NEXTGEN FROM A TECHNICAL PERSPECTIVE
  • 29. MASTER === RELEASE/NEXTGEN FROM A FUNCTIONAL PERSPECTIVE
  • 30. ATTENTION PLEASE LOST OF CODE COMING UP…
  • 31. OVERRIDE DEFAULT CRAWLER public function getHtmlFromContent(InnerBrowser $innerBrowser, $css) { $crawler = $this->getCrawler($innerBrowser); $selector = CssSelector::toXPath($css); $value = $crawler->filterXPath($selector); return $value->html(); } protected function getCrawler(InnerBrowser $innerBrowser) { $reflection = new ReflectionClass(get_class($innerBrowser)); $property = $reflection->getProperty('crawler'); $property->setAccessible(true); return $property->getValue($innerBrowser); }
  • 32. CREATE SECOND PHPBROWSER INSTANCE protected function getPhpBrowserByPage($page) { $phpBrowser = $this->getAlternatePhpBrowser(); $phpBrowser->amOnPage($page); return $phpBrowser; } protected function getAlternatePhpBrowser() { $config = Configuration::config(); $suite = Configuration::suiteSettings('acceptance', $config); $options = $suite['modules']['config']['PhpBrowser']; $options['url'] = $options['alternate-url']; $phpBrowser = new PhpBrowser($options)->_initialize(); $this->setProxyInGuzzle($phpBrowser->guzzle); return $phpBrowser; }
  • 33. GET HTML OF BOTH VERSIONS public function getHtml($page, $path) { $I = $this; $I->amOnPage($page); return $this->getHtmlFromContent( $I->fetchModule('PhpBrowser'), $path); } public function getAlternateHtml($page, $path) { return $this->getHtmlFromContent( $this->getPhpBrowserByPage($page), $path); }
  • 34. ADDING ALTERNATE URL class_name: AcceptanceTester modules: enabled: - PhpBrowser - AcceptanceHelper config: PhpBrowser: url: 'http://www.zendcon.com/' alternate-url: 'http://zendcon.com'
  • 35. COMPARING 2 VERSIONS IN 1 RUN public function seeSameOnVersions($page, $path, $altPath, $message) { $I = $this; list($left, $right) = $this->getContentFromVersions( $page, $path, $altPath); $I->seeEquals($left, $right, $message); } public function getContentFromVersions($page, $path, $altPath) { return array( $this->getHtml($page, $path), $this->getAlternateHtml($page, $altPath) ); }
  • 36. TEST PAGE HEADER public function seeIfPageHeaderIsIdentical(CompareSteps $I) { $I->seeSameOnVersions( HomePage::$URL, 'h2', 'h2', 'Homepage header not identical' ); }
  • 37. TEST SIGNUP FORM public function seeIfFormActionIsIdentical(CompareSteps $I) { $I->seeSameOnVersions( HomePage::$URL, '.rsformbox1', '.rsformbox1', 'Homepage signup form not identical' ); }
  • 38. TEST SIGNUP FORM public function seeIfFormActionIsIdentical(CompareSteps $I) { $I->seeSameOnVersions( HomePage::$URL, '.rsformbox1', '.rsformbox1', 'Homepage signup form not identical' ); } <div class="rsformbox1 title3"> - <form method=“post" id="userForm" action="http://www.zendcon.com/"> + <form method="post" id="userForm" action="http://zendcon.com/">
  • 44. class_name: ApiTester modules: enabled: - ApiHelper - PhpBrowser - REST config: PhpBrowser: url: https://api.github.com REST: url: https://api.github.com
  • 45. public function testGetGists(ApiTester $I) { $I->wantTo('see if we can get the gists listing'); $I->haveHttpHeader('Accept', 'application/vnd.github.beta+json'); $I->sendGet('/users/weierophinney/gists'); $I->seeResponseCodeIs(200); $I->seeResponseIsJson(); } public function testGetGist(ApiTester $I) { $I->wantTo('see if we can get a gist'); $I->haveHttpHeader('Accept', 'application/vnd.github.beta+json'); $I->sendGet('/gists/2c47c9d59f4a5214f0c3'); $I->seeResponseCodeIs(200); $I->seeResponseIsJson(); }
  • 47. /** * @env beta */ public function testGetOldVersionGist(ApiTester $I) { $I->wantTo('see if we can get a gist'); $I->haveHttpHeader('Accept', $I->getAcceptHeader()); $I->sendGet('/gists/2c47c9d59f4a5214f0c3'); $I->seeResponseCodeIs(200); $I->seeResponseIsJson(); $I->seeResponseContainsJson( array('user' => array('login' => ‘weierophinney') )); }
  • 48. SPOT THE DIFFERENCE /** * @env version3 */ public function testGetOldVersionGist(ApiTester $I) { $I->wantTo('see if we can get a gist'); $I->haveHttpHeader('Accept', $I->getAcceptHeader()); $I->sendGet('/gists/2c47c9d59f4a5214f0c3'); $I->seeResponseCodeIs(200); $I->seeResponseIsJson(); $I->seeResponseContainsJson( array('owner' => array('login' => ‘weierophinney') )); }
  • 49. SUITE CONFIG ADDITIONS env: beta: config: data: accept: application/vnd.github.beta+json version3: config: data: accept: application/vnd.github.v3+json
  • 50. CODECEPT RUN API —ENV BETA —ENV VERSION3 TESTING 2 API VERSION IN 1 RUN
  • 52. READY TO DIG DEEPER? USING MODULES
  • 53. CODECEPT GENERATE:SUITE USE YOUR IMAGINATION
  • 54. FILESYSTEM MODULE class MigrateHelper extends CodeceptionModule { public function seeIfLineExistsInFile($file, $line) { $filesystem = $this->getModule('Filesystem'); $filesystem->seeFileFound($file); $filesystem->seeInThisFile($line); } } class HostCest { public function testIfHostsFileIsConfigured(MigrateTester $I) { $I->seeIfLineExistsInFile('/etc/hosts', '127.0.0.1'); } }
  • 55. CLI MODULE class MigrateHelper extends CodeceptionModule { public function seeIfPortIsReachable($host, $port) { $cli = $this->getModule('Cli'); $cli->runShellCommand('nmap '.$host.' -Pn -p '.$port); $cli->seeInShellOutput($port.'/tcp open'); } } class HostCest { public function testIfPortReachable(MigrateTester $I) { $I->seeIfPortIsReachable('www.zendcon.com', 80); } }
  • 56. CLI MODULE class MigrateHelper extends CodeceptionModule { public function seeAddressIsMatchingIp($address, $ip) { $cli = $this->getModule('Cli'); $cli->runShellCommand('host '.$address); $cli->seeInShellOutput($address . ' has address '.$ip); } } class HostCest { public function testIfDnsCanBeResolved(MigrateTester $I) { $I->seeAddressIsMatchingIp('zendcon.com', '50.56.0.87'); } }
  • 57. FTP MODULE class MigrateHelper extends CodeceptionModule { public function seeContentsInRemoteFile($file, $line) { $server = $this->getModule('FTP'); $server->seeFileFound(basename($file), dirname($file)); $server->openFile($file); $server->seeInThisFile($line); } } class HostCest { public function testIfRemoteFileHasContents(MigrateTester $I) { $I->seeContentsInRemoteFile('/etc/hosts', '127.0.0.1'); } }
  • 58. CAVEAT! FTP MODULE SIGNS IN BEFORE EVERY TEST