Using VCR for PHP API Testing

Posted: 2014-07-16 15:38:30

Testing that your code works against an API can take up lots of un-needed time. With this php-vcr library you can do ONE real request that saves a fixture file that will automatically be used with each additional requests!

They have decent docs on setting up but I will walk through them here.

I will base this off a seed phpunit repo I have https://github.com/alnutile/base_library_repo

You will need to add to the composer.json the packages for this library

    "require": {
        "php": ">=5.4.0",
        "ext-curl":        "*",
        "symfony/process": ">=2.3",
        "symfony/event-dispatcher": ">=2.3",
        "guzzle/guzzle":   "~3.7",
        "vlucas/phpdotenv": "1.0.6"
    },
    "require-dev": {
        "phpunit/phpunit": "~3.0",
        "mockery/mockery": "dev-master",
        "php-vcr/php-vcr": "dev-master",
        "php-vcr/phpunit-testlistener-vcr": "dev-master"
    }

I have another post that talks about the dotenv package here

Then if you test folder make a a fixtures folder. So you layout is

.
--test
-----fixtures

And open your phpunit.xml file to add the code to intercept your requests.

#/phpunit.xml


<phpunit backupGlobals="false"
         backupStaticAttributes="false"
         bootstrap="test/bootstrap.php"
         colors="true"
         convertErrorsToExceptions="true"
         convertNoticesToExceptions="true"
         convertWarningsToExceptions="true"
         processIsolation="false"
         stopOnFailure="false"
         syntaxCheck="false"
        >
    <listeners>
        <listener class="PHPUnit_Util_Log_VCR" file="vendor/php-vcr/phpunit-testlistener-vcr/PHPUnit/Util/Log/VCR.php" />
    </listeners>
    <testsuites>
        <testsuite name="Application Test Suite">
            <directory>test</directory>
        </testsuite>
    </testsuites>
</phpunit>

Lastly edit your phpunit bootstrap file to setup VCR

#test/bootstrap.php

<?php

function includeIfExists($file)
{
    if (file_exists($file)) {
        return include $file;
    }
}

if ((!$loader = includeIfExists(__DIR__.'/../vendor/autoload.php')) && (!$loader = includeIfExists(__DIR__.'/../../../.composer/autoload.php'))) {
    die('You must set up the project dependencies, run the following commands:'.PHP_EOL.
        'curl -s http://getcomposer.org/installer | php'.PHP_EOL.
        'php composer.phar install'.PHP_EOL);
}

\VCR\VCR::configure()->setCassettePath(__DIR__ .'/../test/fixtures');

$loader->add('Foo\SauceLabs', __DIR__);

return $loader;

Now you are ready to use the API. This repo has a ton of tests using the api https://github.com/alnutile/saucelabs_client

You will see in this file for example how it is called in the doc blocks

#test/SauceLabs/Tests/JobsTest.php
use SauceLabs\Client;
use VCR\VCR;
use SauceLabs\Tests\BaseTest as Base;

class JobsTest extends Base {

    protected function tearDown()
    {
        m::close();
    }

    /**
     * @test
     * @@vcr get_jobs
     */
    public function get_jobs()
    {
        $username = $_ENV['USERNAME_KEY'];
        VCR::turnOn();
        //VCR::insertCassette('authenticate');
        VCR::insertCassette('get_jobs');
        //Arrange
        $sauce_api = new Client();
        $sauce_api->authenticate($username, $_ENV['TOKEN_PASSWORD'], Client::AUTH_HTTP_PASSWORD);

        //Act
        $response = $sauce_api->api('jobs')->getJobs($username);
        //Assert

        $this->assertGreaterThan(15, count($response));

        // To stop recording requests, eject the cassette
        VCR::eject();
        // Turn off VCR to stop intercepting requests
        VCR::turnOff();
    }

After the first time you run that you will have a new "cassette" in the test/fixtures folder that you can use as needed

#test/fixtures/get_jobs

-
    request:
        method: GET
        url: 'https://saucelabs.com/rest/v1/api-test-user/jobs'
        headers:
            Host: saucelabs.com
            Accept: application/vnd.SauceLabs.beta+json
            User-Agent: 'php-github-api (http://github.com/alnutile/saucelabs_client)'
            Authorization: 'Basic YmVoYXQtc2VlZDpmYzViNjg4YS1mMjdjLTRjNzMtYTkxNC1lYjVkN2UyY2RmMWU='
            Content-Length: '0'
    response:
        status: 200
        headers:
            Server: nginx
            Date: 'Fri, 11 Jul 2014 11:03:19 GMT'
            Content-Type: 'application/json; charset=utf-8'
            Transfer-Encoding: chunked
            Connection: keep-alive
            X-Backend: mix
        body: '[{"id": "79bd34f42d584da6ad59c051388134d9"}, {"id": "d75177a863ec4a458c7222813e10ee84"}, {"id": "67591976001c4c5a9522b93281e0e8ef"}, {"id": "ada6876f799d4b589ef0e2c4069c7438"}, {"id": "3e676ac921aa43f5a5628d231ca7115d"}, {"id": "222cdddafb9e4c3fb0722bccc9891a15"}, {"id": "6393dc7ca1ea447eb509b5e1dd6821ac"}, {"id": "789004fc2ec34d0d8e03945759fc25b0"}, {"id": "3331badd2da140d08613a786257d177d"}, {"id": "9437a50a354e4fca8252447b03d21348"}, {"id": "dec07ca1c30e40f4a693de7f7a102eab"}, {"id": "3a1a0fb2d4be4580b00a3e35b86aa6fa"}, {"id": "55de27651bf14c92b901cbd0a62b1603"}, {"id": "7e12ec786ad544008c5f4e3e4340d5a8"}, {"id": "a8edb7ab8a8f408a9b0829cc45ca4563"}, {"id": "b67a4d7187cc4dc8ad661ef7045d15e9"}]'
-
    request:
        method: GET
        url: 'https://saucelabs.com/rest/v1/behat-seed/jobs'
        headers:
            Host: saucelabs.com
            Accept: application/vnd.SauceLabs.beta+json
            User-Agent: 'php-github-api (http://github.com/alnutile/saucelabs_client)'
            Authorization: 'Basic YmVoYXQdtc2VlZssDpmYzViNjdfasdfg4YS1mMjdrerjLTRjNzMtYTkxNC1l3eYjVkN2UyY2RmMadsfWUj='
            Content-Length: '0'
    response:
        status: 200
        headers:
            Server: nginx
            Date: 'Fri, 11 Jul 2014 13:41:38 GMT'
            Content-Type: 'application/json; charset=utf-8'
            Transfer-Encoding: chunked
            Connection: keep-alive
            X-Backend: mix
        body: '[{"id": "3a4136e1bb6f4f6b8cae6fbd0bf2e6aa"}, {"id": "1cde7b77e8744ff5b6198489ceffce81"}, {"id": "79bd34f42d584da6ad59c051388134d9"}, {"id": "d75177a863ec4a458c7222813e10ee84"}, {"id": "67591976001c4c5a9522b93281e0e8ef"}, {"id": "ada6876f799d4b589ef0e2c4069c7438"}, {"id": "3e676ac921aa43f5a5628d231ca7115d"}, {"id": "222cdddafb9e4c3fb0722bccc9891a15"}, {"id": "6393dc7ca1ea447eb509b5e1dd6821ac"}, {"id": "789004fc2ec34d0d8e03945759fc25b0"}, {"id": "3331badd2da140d08613a786257d177d"}, {"id": "9437a50a354e4fca8252447b03d21348"}, {"id": "dec07ca1c30e40f4a693de7f7a102eab"}, {"id": "3a1a0fb2d4be4580b00a3e35b86aa6fa"}, {"id": "55de27651bf14c92b901cbd0a62b1603"}, {"id": "7e12ec786ad544008c5f4e3e4340d5a8"}, {"id": "a8edb7ab8a8f408a9b0829cc45ca4563"}, {"id": "b67a4d7187cc4dc8ad661ef7045d15e9"}]'

That library should be a big help to try it out. You just need a Saucelabs account and make a file in the root of your folder called .env as noted in the README with your username and token for saucelabs and then run bin/phpunit.


Tags:

php api testing