A case study about the PHP-VCR: How it is used at a big Symfony2 project together with Behat/Selenium/PhantomJS and what kind of pitfalls exist and how to tackle them.
Pascal ThormeierPassionate Web Developer with focus on Symfony2 and other PHP applications
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
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
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();
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
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