PHP-VCR behat case study

Pascal Thormeier
Pascal ThormeierPassionate Web Developer with focus on Symfony2 and other PHP applications
ZürichPHP UG 18.06.2015

Pascal Thormeier
Setup
Big Symfony2 project for large Swiss
company

Multiple attached APIs

Tests in both PHPUnit and Behat/PhantomJS

Gitlab CI and vagrant for development
ONCE UPON A TIME
History
Testing with manually created fixtures

Mocks had to be adjusted when APIs
changed

Using Guzzle's mock plugin

Symfony's profiler helped out quite a lot...
Mocking:

• Do API call you would like to mock

• Copy/paste response to JSON/XML file

• Adjust to test cases

• Re-do whole fixture when small things changed
History
Behat tests couldn't really be mocked

Built an application that proxies API calls
and runs in the back in an own container

Loads of problems with that solution
History
Switching to PHP-VCR

Behat testing and mocking became very
well possible

Old way of creating fixtures was no longer
necessary
History
WHAT ARE WE DOING
NOW?
Behat
Testing framework

Works with different so called drivers

Tests are written in Gherkin

We're using the Selenium2 and Symfony
Web drivers
Selenium
PhantomJS as headless browser

PHP -> node.js -> PHP

... which leads to a problem
Selenium
Two different, independent PHP processes

Which fixture should the application load?
Selenium
Let's just use a cookie.
Selenium
<?php	
class AcmeContext extends MinkContext 	
{	
const COOKIE_NAME = 'BehatCassetteName';	
!
// ...	
!
public function before(BeforeScenarioScope $scope)	
{	
$this->getSession()->setCookie(	
self::COOKIE_NAME,	
$this->getCassetteName($scope)	
);	
}	
!
// ...	
!
}
Selenium
<?php	
class AcmeContext extends MinkContext 	
{	
!
// ...	
!
public function getCasetteName($scope)	
{	
return 'fixtures/'	
. self::normalize($scope->getFeature()->getTitle())	
. '/'	
. self::normalize($scope->getScenario()->getTitle())	
;	
}	
!
public static function normalize($string)	
{	
return trim(preg_replace(	
'/[^a-zA-Z0-9]+/', '_', $string	
), '_');	
}	
!
// ...	
!
}
Gherkin
Feature: Some terse yet descriptive text of what is desired	
In order to realize a named business value	
As an explicit system actor	
I want to gain some beneficial outcome which furthers the goal	
!
Additional text...	
!
Scenario: Some determinable business situation	
Given some precondition	
And some other precondition	
When some action by the actor	
And some other action	
And yet another action	
Then some testable outcome is achieved	
And something else we can check happens too	
!
Scenario: A different situation	
...
Selenium
<?php	
// web/app_test.php - Remove this file while deployment!	
!
// ...	
!
// Execute standard SF2 stuff	
$kernel = new AppKernel('test', true);	
$kernel->loadClassCache();	
Request::enableHttpMethodParameterOverride();	
$request = Request::createFromGlobals();	
!
// Set up VCR with fixture name from cookie	
$fixture = $request->cookies->get(AcmeContext::COOKIE_NAME, null);	
if (!$fixture) {	
$fixture = AcmeContext::normalize($request->getUri());	
}	
VCR::turnOn(); 	
VCR::insertCassette('../tests/' . $fixture . '.json');	
!
// Execute standard SF2 stuff	
$response = $kernel->handle($request);	
$response->send();	
$kernel->terminate($request, $response);	
!
// Save the fixture	
VCR::eject();	
VCR::turnOff();
Selenium
Neat side effects:

• Developing without internet!

• Change API responses for development
Minor pitfall:

• PhantomJS doesn't send this cookie when
doing AJAX

• Fixtures for AJAX would be named after the
URL, which works but isn't as nice

• You have to set the cookie manually in JS again
Selenium
WebDriver
We want this in the SF WebDriver as well

Move it from app_test to AppKernel

Keep app_test.php as entry point for
PhantomJS
WebDriver
<?php	
class AppKernel extends Kernel	
{	
// ...	
public function handle(Request $request, ...)	
{	
if ('test' === $this->getEnvironment()) {	
$fixture = $request->cookies->get(	
AcmeContext::COOKIE_NAME, null	
);	
!
if (!$fixture) {	
$fixture = AcmeContext::normalize(	
$request->getUri()	
);	
}	
!
VCR::turnOn(); 	
VCR::insertCassette('../tests/' . $fixture . '.json');	
}	
!
return parent::handle($request, ...);	
}	
// ...	
}
WebDriver
Would only need minor adjustments to also
work in PHPUnit/Symfony WebTestCase
GitlabCI
CI is executing tests as well

Tests might not be mocked

Test will be mocked

Conflicts while making a new build
GitlabCI
<?php	
// ...	
!
if ($container->hasParameter('is_ci')) {	
VCR::configure()->setMode(VCR::MODE_NONE);	
}	
!
// ...
WRAP UP
Wrap up
PHP-VCR is awesome

But switching all fixtures to PHP-VCR might
be a lot of work

But you don't need to write them
yourselves anymore
Wrap up
Some pitfalls:

• Tests without fixtures

• Setup depending on framework might be difficult

• Not very transparent where data comes from
inside tests

• First test run to write all the fixtures is slow
Wrap up
Would highly recommend it because it
saves you a lot of time, work and nerves
Info
Info and documentation: http://php-
vcr.github.io

Source: https://github.com/php-vcr/php-vcr

VCR (ruby): https://github.com/vcr/vcr

Follow: @pthormeier and @adrian_philipp
1 of 28

Recommended

PHP-VCR Lightningtalk by
PHP-VCR LightningtalkPHP-VCR Lightningtalk
PHP-VCR LightningtalkAdrian Philipp
31.9K views9 slides
Building JBoss AS 7 for Fedora by
Building JBoss AS 7 for FedoraBuilding JBoss AS 7 for Fedora
Building JBoss AS 7 for Fedorawolfc71
514 views33 slides
Devoxx France: Développement JAVA avec un IDE dans le Cloud: Yes we can ! by
Devoxx France: Développement JAVA avec un IDE dans le Cloud: Yes we can !Devoxx France: Développement JAVA avec un IDE dans le Cloud: Yes we can !
Devoxx France: Développement JAVA avec un IDE dans le Cloud: Yes we can !Florent BENOIT
1.2K views18 slides
OSCamp 2019 | #3 Ansible: Automated Tests of Ansible code with GitLab, Vagran... by
OSCamp 2019 | #3 Ansible: Automated Tests of Ansible code with GitLab, Vagran...OSCamp 2019 | #3 Ansible: Automated Tests of Ansible code with GitLab, Vagran...
OSCamp 2019 | #3 Ansible: Automated Tests of Ansible code with GitLab, Vagran...NETWAYS
76 views22 slides
Paris Monitoring meetup #1 - Zabbix at BlaBlaCar by
Paris Monitoring meetup #1 - Zabbix at BlaBlaCarParis Monitoring meetup #1 - Zabbix at BlaBlaCar
Paris Monitoring meetup #1 - Zabbix at BlaBlaCarJean Baptiste Favre
1.9K views26 slides
The MetaCPAN VM for Dummies Part One (Installation) by
The MetaCPAN VM for Dummies Part One (Installation)The MetaCPAN VM for Dummies Part One (Installation)
The MetaCPAN VM for Dummies Part One (Installation)Olaf Alders
1.8K views18 slides

More Related Content

What's hot

Orchestrated Functional Testing with Puppet-spec and Mspectator - PuppetConf ... by
Orchestrated Functional Testing with Puppet-spec and Mspectator - PuppetConf ...Orchestrated Functional Testing with Puppet-spec and Mspectator - PuppetConf ...
Orchestrated Functional Testing with Puppet-spec and Mspectator - PuppetConf ...Puppet
3K views32 slides
CodeIgniter Ant Scripting by
CodeIgniter Ant ScriptingCodeIgniter Ant Scripting
CodeIgniter Ant ScriptingAlbert Rosa
1.3K views23 slides
Code igniter unittest-part1 by
Code igniter unittest-part1Code igniter unittest-part1
Code igniter unittest-part1Albert Rosa
7.2K views20 slides
Flask With Server-Sent Event by
Flask With Server-Sent EventFlask With Server-Sent Event
Flask With Server-Sent EventTencent
4.4K views37 slides
Ava unit test by
Ava unit testAva unit test
Ava unit testMohamed Ahmed
85 views9 slides
Cramp websockets by
Cramp websocketsCramp websockets
Cramp websocketsAntônio Roberto Silva
558 views38 slides

What's hot(20)

Orchestrated Functional Testing with Puppet-spec and Mspectator - PuppetConf ... by Puppet
Orchestrated Functional Testing with Puppet-spec and Mspectator - PuppetConf ...Orchestrated Functional Testing with Puppet-spec and Mspectator - PuppetConf ...
Orchestrated Functional Testing with Puppet-spec and Mspectator - PuppetConf ...
Puppet3K views
CodeIgniter Ant Scripting by Albert Rosa
CodeIgniter Ant ScriptingCodeIgniter Ant Scripting
CodeIgniter Ant Scripting
Albert Rosa1.3K views
Code igniter unittest-part1 by Albert Rosa
Code igniter unittest-part1Code igniter unittest-part1
Code igniter unittest-part1
Albert Rosa7.2K views
Flask With Server-Sent Event by Tencent
Flask With Server-Sent EventFlask With Server-Sent Event
Flask With Server-Sent Event
Tencent4.4K views
Futureproof angular 1.x applications - yannick houbrix by Axxes IT Consultancy
Futureproof angular 1.x  applications - yannick houbrixFutureproof angular 1.x  applications - yannick houbrix
Futureproof angular 1.x applications - yannick houbrix
Managing Complexity with Module::Release by brian d foy
Managing Complexity with Module::ReleaseManaging Complexity with Module::Release
Managing Complexity with Module::Release
brian d foy1.5K views
Implement server push in flask framework by Chi-Chia Huang
Implement server push in flask frameworkImplement server push in flask framework
Implement server push in flask framework
Chi-Chia Huang7.8K views
Vagrant - the essence of DevOps in a tool by Paul Stack
Vagrant - the essence of DevOps in a toolVagrant - the essence of DevOps in a tool
Vagrant - the essence of DevOps in a tool
Paul Stack1.3K views
GTLAB Overview by marpierc
GTLAB OverviewGTLAB Overview
GTLAB Overview
marpierc667 views
Full stack, Full run, Full test by Taras Slipets
Full stack, Full run, Full testFull stack, Full run, Full test
Full stack, Full run, Full test
Taras Slipets240 views
Intro to testing Javascript with jasmine by Timothy Oxley
Intro to testing Javascript with jasmineIntro to testing Javascript with jasmine
Intro to testing Javascript with jasmine
Timothy Oxley9.4K views
Introducing Revel by Zhebr
Introducing RevelIntroducing Revel
Introducing Revel
Zhebr405 views
Continuous integration with Git & CI Joe by Shawn Price
Continuous integration with Git & CI JoeContinuous integration with Git & CI Joe
Continuous integration with Git & CI Joe
Shawn Price2.2K views

Similar to PHP-VCR behat case study

Continous Delivering a PHP application by
Continous Delivering a PHP applicationContinous Delivering a PHP application
Continous Delivering a PHP applicationJavier López
2.6K views82 slides
One commit, one release. Continuously delivering a Symfony project. by
One commit, one release. Continuously delivering a Symfony project.One commit, one release. Continuously delivering a Symfony project.
One commit, one release. Continuously delivering a Symfony project.Javier López
3.2K views80 slides
Deploying Symfony | symfony.cat by
Deploying Symfony | symfony.catDeploying Symfony | symfony.cat
Deploying Symfony | symfony.catPablo Godel
2.8K views149 slides
Altitude San Francisco 2018: Testing with Fastly Workshop by
Altitude San Francisco 2018: Testing with Fastly WorkshopAltitude San Francisco 2018: Testing with Fastly Workshop
Altitude San Francisco 2018: Testing with Fastly WorkshopFastly
181 views66 slides
RichFaces - Testing on Mobile Devices by
RichFaces - Testing on Mobile DevicesRichFaces - Testing on Mobile Devices
RichFaces - Testing on Mobile DevicesPavol Pitoňák
12.4K views53 slides
Release with confidence by
Release with confidenceRelease with confidence
Release with confidenceJohn Congdon
1.8K views35 slides

Similar to PHP-VCR behat case study(20)

Continous Delivering a PHP application by Javier López
Continous Delivering a PHP applicationContinous Delivering a PHP application
Continous Delivering a PHP application
Javier López2.6K views
One commit, one release. Continuously delivering a Symfony project. by Javier López
One commit, one release. Continuously delivering a Symfony project.One commit, one release. Continuously delivering a Symfony project.
One commit, one release. Continuously delivering a Symfony project.
Javier López3.2K views
Deploying Symfony | symfony.cat by Pablo Godel
Deploying Symfony | symfony.catDeploying Symfony | symfony.cat
Deploying Symfony | symfony.cat
Pablo Godel2.8K views
Altitude San Francisco 2018: Testing with Fastly Workshop by Fastly
Altitude San Francisco 2018: Testing with Fastly WorkshopAltitude San Francisco 2018: Testing with Fastly Workshop
Altitude San Francisco 2018: Testing with Fastly Workshop
Fastly181 views
RichFaces - Testing on Mobile Devices by Pavol Pitoňák
RichFaces - Testing on Mobile DevicesRichFaces - Testing on Mobile Devices
RichFaces - Testing on Mobile Devices
Pavol Pitoňák12.4K views
Release with confidence by John Congdon
Release with confidenceRelease with confidence
Release with confidence
John Congdon1.8K views
Selenium & PHPUnit made easy with Steward (Berlin, April 2017) by Ondřej Machulda
Selenium & PHPUnit made easy with Steward (Berlin, April 2017)Selenium & PHPUnit made easy with Steward (Berlin, April 2017)
Selenium & PHPUnit made easy with Steward (Berlin, April 2017)
Ondřej Machulda1.4K views
"Applied Enterprise Metaprogramming in JavaScript", Vladyslav Dukhin by Fwdays
"Applied Enterprise Metaprogramming in JavaScript", Vladyslav Dukhin"Applied Enterprise Metaprogramming in JavaScript", Vladyslav Dukhin
"Applied Enterprise Metaprogramming in JavaScript", Vladyslav Dukhin
Fwdays83 views
Python Flask app deployed to OPenShift using Wercker CI by Bruno Rocha
Python Flask app deployed to OPenShift using Wercker CIPython Flask app deployed to OPenShift using Wercker CI
Python Flask app deployed to OPenShift using Wercker CI
Bruno Rocha2.3K views
Monitoring kubernetes with prometheus by Brice Fernandes
Monitoring kubernetes with prometheusMonitoring kubernetes with prometheus
Monitoring kubernetes with prometheus
Brice Fernandes1.2K views
Angularjs - Unit testing introduction by Nir Kaufman
Angularjs - Unit testing introductionAngularjs - Unit testing introduction
Angularjs - Unit testing introduction
Nir Kaufman9.7K views
Getting started with puppet and vagrant (1) by Puppet
Getting started with puppet and vagrant (1)Getting started with puppet and vagrant (1)
Getting started with puppet and vagrant (1)
Puppet1.4K views
Build Your Own CaaS (Container as a Service) by HungWei Chiu
Build Your Own CaaS (Container as a Service)Build Your Own CaaS (Container as a Service)
Build Your Own CaaS (Container as a Service)
HungWei Chiu726 views
Finally, Professional Frontend Dev with ReactJS, WebPack & Symfony (Symfony C... by Ryan Weaver
Finally, Professional Frontend Dev with ReactJS, WebPack & Symfony (Symfony C...Finally, Professional Frontend Dev with ReactJS, WebPack & Symfony (Symfony C...
Finally, Professional Frontend Dev with ReactJS, WebPack & Symfony (Symfony C...
Ryan Weaver13.7K views
Using HttpKernelInterface for Painless Integration by CiaranMcNulty
Using HttpKernelInterface for Painless IntegrationUsing HttpKernelInterface for Painless Integration
Using HttpKernelInterface for Painless Integration
CiaranMcNulty1.1K views
Learn basic ansible using docker by Larry Cai
Learn basic ansible using dockerLearn basic ansible using docker
Learn basic ansible using docker
Larry Cai6.9K views
Testing - Selenium? Rich-Clients? Containers? by Tobias Schneck
Testing - Selenium? Rich-Clients? Containers?Testing - Selenium? Rich-Clients? Containers?
Testing - Selenium? Rich-Clients? Containers?
Tobias Schneck567 views

Recently uploaded

Info Session November 2023.pdf by
Info Session November 2023.pdfInfo Session November 2023.pdf
Info Session November 2023.pdfAleksandraKoprivica4
13 views15 slides
Vertical User Stories by
Vertical User StoriesVertical User Stories
Vertical User StoriesMoisés Armani Ramírez
14 views16 slides
20231123_Camunda Meetup Vienna.pdf by
20231123_Camunda Meetup Vienna.pdf20231123_Camunda Meetup Vienna.pdf
20231123_Camunda Meetup Vienna.pdfPhactum Softwareentwicklung GmbH
41 views73 slides
Mini-Track: Challenges to Network Automation Adoption by
Mini-Track: Challenges to Network Automation AdoptionMini-Track: Challenges to Network Automation Adoption
Mini-Track: Challenges to Network Automation AdoptionNetwork Automation Forum
13 views27 slides
Case Study Copenhagen Energy and Business Central.pdf by
Case Study Copenhagen Energy and Business Central.pdfCase Study Copenhagen Energy and Business Central.pdf
Case Study Copenhagen Energy and Business Central.pdfAitana
16 views3 slides
Democratising digital commerce in India-Report by
Democratising digital commerce in India-ReportDemocratising digital commerce in India-Report
Democratising digital commerce in India-ReportKapil Khandelwal (KK)
18 views161 slides

Recently uploaded(20)

Case Study Copenhagen Energy and Business Central.pdf by Aitana
Case Study Copenhagen Energy and Business Central.pdfCase Study Copenhagen Energy and Business Central.pdf
Case Study Copenhagen Energy and Business Central.pdf
Aitana16 views
STPI OctaNE CoE Brochure.pdf by madhurjyapb
STPI OctaNE CoE Brochure.pdfSTPI OctaNE CoE Brochure.pdf
STPI OctaNE CoE Brochure.pdf
madhurjyapb14 views
"Running students' code in isolation. The hard way", Yurii Holiuk by Fwdays
"Running students' code in isolation. The hard way", Yurii Holiuk "Running students' code in isolation. The hard way", Yurii Holiuk
"Running students' code in isolation. The hard way", Yurii Holiuk
Fwdays17 views
Igniting Next Level Productivity with AI-Infused Data Integration Workflows by Safe Software
Igniting Next Level Productivity with AI-Infused Data Integration Workflows Igniting Next Level Productivity with AI-Infused Data Integration Workflows
Igniting Next Level Productivity with AI-Infused Data Integration Workflows
Safe Software280 views
6g - REPORT.pdf by Liveplex
6g - REPORT.pdf6g - REPORT.pdf
6g - REPORT.pdf
Liveplex10 views
Future of AR - Facebook Presentation by ssuserb54b561
Future of AR - Facebook PresentationFuture of AR - Facebook Presentation
Future of AR - Facebook Presentation
ssuserb54b56115 views
ESPC 2023 - Protect and Govern your Sensitive Data with Microsoft Purview in ... by Jasper Oosterveld
ESPC 2023 - Protect and Govern your Sensitive Data with Microsoft Purview in ...ESPC 2023 - Protect and Govern your Sensitive Data with Microsoft Purview in ...
ESPC 2023 - Protect and Govern your Sensitive Data with Microsoft Purview in ...
Piloting & Scaling Successfully With Microsoft Viva by Richard Harbridge
Piloting & Scaling Successfully With Microsoft VivaPiloting & Scaling Successfully With Microsoft Viva
Piloting & Scaling Successfully With Microsoft Viva

PHP-VCR behat case study

  • 2. Setup Big Symfony2 project for large Swiss company Multiple attached APIs Tests in both PHPUnit and Behat/PhantomJS Gitlab CI and vagrant for development
  • 3. ONCE UPON A TIME
  • 4. History Testing with manually created fixtures Mocks had to be adjusted when APIs changed Using Guzzle's mock plugin Symfony's profiler helped out quite a lot...
  • 5. Mocking: • Do API call you would like to mock • Copy/paste response to JSON/XML file • Adjust to test cases • Re-do whole fixture when small things changed History
  • 6. Behat tests couldn't really be mocked Built an application that proxies API calls and runs in the back in an own container Loads of problems with that solution History
  • 7. Switching to PHP-VCR Behat testing and mocking became very well possible Old way of creating fixtures was no longer necessary History
  • 8. WHAT ARE WE DOING NOW?
  • 9. Behat Testing framework Works with different so called drivers Tests are written in Gherkin We're using the Selenium2 and Symfony Web drivers
  • 10. Selenium PhantomJS as headless browser PHP -> node.js -> PHP ... which leads to a problem
  • 11. Selenium Two different, independent PHP processes Which fixture should the application load?
  • 13. Selenium <?php class AcmeContext extends MinkContext { const COOKIE_NAME = 'BehatCassetteName'; ! // ... ! public function before(BeforeScenarioScope $scope) { $this->getSession()->setCookie( self::COOKIE_NAME, $this->getCassetteName($scope) ); } ! // ... ! }
  • 14. Selenium <?php class AcmeContext extends MinkContext { ! // ... ! public function getCasetteName($scope) { return 'fixtures/' . self::normalize($scope->getFeature()->getTitle()) . '/' . self::normalize($scope->getScenario()->getTitle()) ; } ! public static function normalize($string) { return trim(preg_replace( '/[^a-zA-Z0-9]+/', '_', $string ), '_'); } ! // ... ! }
  • 15. Gherkin Feature: Some terse yet descriptive text of what is desired In order to realize a named business value As an explicit system actor I want to gain some beneficial outcome which furthers the goal ! Additional text... ! Scenario: Some determinable business situation Given some precondition And some other precondition When some action by the actor And some other action And yet another action Then some testable outcome is achieved And something else we can check happens too ! Scenario: A different situation ...
  • 16. Selenium <?php // web/app_test.php - Remove this file while deployment! ! // ... ! // Execute standard SF2 stuff $kernel = new AppKernel('test', true); $kernel->loadClassCache(); Request::enableHttpMethodParameterOverride(); $request = Request::createFromGlobals(); ! // Set up VCR with fixture name from cookie $fixture = $request->cookies->get(AcmeContext::COOKIE_NAME, null); if (!$fixture) { $fixture = AcmeContext::normalize($request->getUri()); } VCR::turnOn(); VCR::insertCassette('../tests/' . $fixture . '.json'); ! // Execute standard SF2 stuff $response = $kernel->handle($request); $response->send(); $kernel->terminate($request, $response); ! // Save the fixture VCR::eject(); VCR::turnOff();
  • 17. Selenium Neat side effects: • Developing without internet! • Change API responses for development
  • 18. Minor pitfall: • PhantomJS doesn't send this cookie when doing AJAX • Fixtures for AJAX would be named after the URL, which works but isn't as nice • You have to set the cookie manually in JS again Selenium
  • 19. WebDriver We want this in the SF WebDriver as well Move it from app_test to AppKernel Keep app_test.php as entry point for PhantomJS
  • 20. WebDriver <?php class AppKernel extends Kernel { // ... public function handle(Request $request, ...) { if ('test' === $this->getEnvironment()) { $fixture = $request->cookies->get( AcmeContext::COOKIE_NAME, null ); ! if (!$fixture) { $fixture = AcmeContext::normalize( $request->getUri() ); } ! VCR::turnOn(); VCR::insertCassette('../tests/' . $fixture . '.json'); } ! return parent::handle($request, ...); } // ... }
  • 21. WebDriver Would only need minor adjustments to also work in PHPUnit/Symfony WebTestCase
  • 22. GitlabCI CI is executing tests as well Tests might not be mocked Test will be mocked Conflicts while making a new build
  • 23. GitlabCI <?php // ... ! if ($container->hasParameter('is_ci')) { VCR::configure()->setMode(VCR::MODE_NONE); } ! // ...
  • 25. Wrap up PHP-VCR is awesome But switching all fixtures to PHP-VCR might be a lot of work But you don't need to write them yourselves anymore
  • 26. Wrap up Some pitfalls: • Tests without fixtures • Setup depending on framework might be difficult • Not very transparent where data comes from inside tests • First test run to write all the fixtures is slow
  • 27. Wrap up Would highly recommend it because it saves you a lot of time, work and nerves
  • 28. Info Info and documentation: http://php- vcr.github.io Source: https://github.com/php-vcr/php-vcr VCR (ruby): https://github.com/vcr/vcr Follow: @pthormeier and @adrian_philipp