How to integrate PHPUnit with PHP-VCR

Step1: Install php-vcr library

composer require php-vcr/phpunit-testlistener-vcr

Step2: Add below to your phpunit.xml

<listeners>

<listener class="VCR\PHPUnit\TestListener\VCRTestListener" file="vendor/php-vcr/phpunit-testlistener-vcr/src/VCRTestListener.php" />

</listeners>

Step3: Create ‘fixtures’ directory. (By default api response will be stored under tests/fixtures)

mkdir -p tests/fixtures

How to use it in your test suites

Step1: Declare VCR class.

use VCR\VCR;

Step2: Add @vcr annotation for your test case. (That indicates where you want to store and replay for the external api response.)

* @vcr github.yml

Here is an example

<?php



namespace Tests\Unit;



use VCR\VCR;

use GuzzleHttp\Client;

use Tests\TestCase;



class PhpVCrTest extends TestCase

{

public function setUp(): void

{

parent::setUp();

}



/**

* @test

* @vcr github.yml

* @group PhpVcrTest

*/

public function shouldUseGitHubVcrRecord()

{

$client = app(Client::class);



$response = $client->request('GET', 'https://api.github.com/users/yama');



$this->assertEquals('yama',json_decode($response->getBody())->login);

}

}

When you run above test case, you would see it costs 1.45 seconds. That is because the test case would access api.github.com in the first time.

Also you would see a file called github.yml is generated under tests/fixtures. The file has below content:

-

request:

method: GET

url: 'https://api.github.com/users/yama'

headers:

Host: api.github.com

Accept-Encoding: null

User-Agent: 'GuzzleHttp/6.3.3 curl/7.64.1 PHP/7.3.5'

Accept: null

response:

status:

http_version: '1.1'

code: '200'

message: OK

headers:

Date: 'Wed, 31 Jul 2019 02:21:41 GMT'

Content-Type: 'application/json; charset=utf-8'

Content-Length: '1284'

Server: GitHub.com

Status: '200 OK'

X-RateLimit-Limit: '60'

X-RateLimit-Remaining: '50'

X-RateLimit-Reset: '1564542845'

Cache-Control: 'public, max-age=60, s-maxage=60'

Vary: 'Accept, Accept-Encoding'

ETag: '"4f615d2b3dd8c3164c19ea88c4ff3ca6"'

Last-Modified: 'Thu, 25 Jul 2019 10:15:54 GMT'

X-GitHub-Media-Type: 'github.v3; format=json'

Access-Control-Expose-Headers: 'ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type'

Access-Control-Allow-Origin: '*'

Strict-Transport-Security: 'max-age=31536000; includeSubdomains; preload'

X-Frame-Options: deny

X-Content-Type-Options: nosniff

X-XSS-Protection: '1; mode=block'

Referrer-Policy: 'origin-when-cross-origin, strict-origin-when-cross-origin'

Content-Security-Policy: 'default-src ''none'''

X-GitHub-Request-Id: '0937:8BF3:478098:554627:5D40FB34'

body: "{

\"login\": \"yama\",

\"id\": 73999,

\"node_id\": \"MDQ6VXNlcjczOTk5\",

\"avatar_url\": \"https://avatars2.githubusercontent.com/u/73999?v=4\",

\"gravatar_id\": \"\",

\"url\": \"https://api.github.com/users/yama\",

\"html_url\": \"https://github.com/yama\",

\"followers_url\": \"https://api.github.com/users/yama/followers\",

\"following_url\": \"https://api.github.com/users/yama/following{/other_user}\",

\"gists_url\": \"https://api.github.com/users/yama/gists{/gist_id}\",

\"starred_url\": \"https://api.github.com/users/yama/starred{/owner}{/repo}\",

\"subscriptions_url\": \"https://api.github.com/users/yama/subscriptions\",

\"organizations_url\": \"https://api.github.com/users/yama/orgs\",

\"repos_url\": \"https://api.github.com/users/yama/repos\",

\"events_url\": \"https://api.github.com/users/yama/events{/privacy}\",

\"received_events_url\": \"https://api.github.com/users/yama/received_events\",

\"type\": \"User\",

\"site_admin\": false,

\"name\": \"yamamoto\",

\"company\": null,

\"blog\": \"http://kyms.jp\",

\"location\": \"fukuoka\",

\"email\": null,

\"hireable\": null,

\"bio\": \"http://www.amazon.co.jp/registry/wishlist/EA86H7WT9NBB\",

\"public_repos\": 134,

\"public_gists\": 5,

\"followers\": 42,

\"following\": 53,

\"created_at\": \"2009-04-15T10:22:28Z\",

\"updated_at\": \"2019-07-25T10:15:54Z\"

}

"

Now run above test case again. It would automatically use recorded response at github.yml . So it only costs 489ms.

Summary

PHP-VCR is handy and easy to use. It would be widely used for integration automation testings. Below diagram briefly explains its inner logic.

If we want to hide secret parameters in request or response, we would just modify request/response in the @vcr specified file. As long as php-vcr could find matched request, it would return the corresponding response. It is really cool, isn’t it?