php-vcr / php-vcr
Record your test suite's HTTP interactions and replay them during future test runs for fast, deterministic, accurate tests.
Requires
- php: ^8,<8.2|>=8.2.9,<8.6
- ext-curl: *
- beberlei/assert: ^3.2.5
- symfony/event-dispatcher: ^4|^5|^6|^7
- symfony/event-dispatcher-contracts: ^1|^2|^3
- symfony/yaml: ^3|^4|^5|^6|^7
Requires (Dev)
- ext-soap: *
- editorconfig-checker/editorconfig-checker: ^10.3
- friendsofphp/php-cs-fixer: ^3.0
- guzzlehttp/guzzle: ^7
- mikey179/vfsstream: ^1.6.10
- phpstan/extension-installer: ^1.1
- phpstan/phpstan: ^1
- phpstan/phpstan-beberlei-assert: ^1
- phpstan/phpstan-phpunit: ^1
- phpunit/phpunit: ^9.5.10|^10.5|^11.0
- symfony/http-client: ^5.4|^6.0|^7.0
- thecodingmachine/phpstan-strict-rules: ^1
This package is auto-updated.
Last update: 2026-07-05 22:55:58 UTC
README
This is a port of the VCR Ruby library to PHP.
Record your test suite's HTTP interactions and replay them during future test runs for fast, deterministic, accurate tests. A bit of documentation can be found on the php-vcr website.
Disclaimer: Doing this in PHP is not as easy as in programming languages which support monkey patching (I'm looking at you, Ruby)
Features
- Automatically records and replays your HTTP(s) interactions with minimal setup/configuration code.
- Supports common http functions and extensions — see Supported HTTP libraries below
- The same request can receive different responses in different tests -- just use different cassettes.
- Disables all HTTP requests that you don't explicitly allow by setting the record mode
- Request matching is configurable based on HTTP method, URI, host, path, body and headers, or you can easily implement a custom request matcher to handle any need.
- The recorded requests and responses are stored on disk in a serialization format of your choice (currently YAML and JSON are built in, and you can easily implement your own custom serializer)
- Supports PHPUnit annotations.
Usage example
Using static method calls:
class VCRTest extends TestCase { public function testShouldInterceptStreamWrapper() { // After turning on the VCR will intercept all requests \VCR\VCR::turnOn(); // Record requests and responses in cassette file 'example' \VCR\VCR::insertCassette('example'); // Following request will be recorded once and replayed in future test runs $result = file_get_contents('http://example.com'); $this->assertNotEmpty($result); // To stop recording requests, eject the cassette \VCR\VCR::eject(); // Turn off VCR to stop intercepting requests \VCR\VCR::turnOff(); } public function testShouldThrowExceptionIfNoCasettePresent() { $this->setExpectedException( 'BadMethodCallException', "Invalid http request. No cassette inserted. Please make sure to insert " . "a cassette in your unit test using VCR::insertCassette('name');" ); \VCR\VCR::turnOn(); // If there is no cassette inserted, a request throws an exception file_get_contents('http://example.com'); } }
You can use annotations in PHPUnit by using phpunit-testlistener-vcr:
class VCRTest extends TestCase { /** * @vcr unittest_annotation_test */ public function testInterceptsWithAnnotations() { // Requests are intercepted and stored into tests/fixtures/unittest_annotation_test. $result = file_get_contents('http://google.com'); $this->assertEquals('This is a annotation test dummy.', $result, 'Call was not intercepted (using annotations).'); // VCR is automatically turned on and off. } }
Supported HTTP libraries
All three hooks are enabled by default when you call VCR::turnOn(). No extra configuration is required.
| Hook name | Intercepted libraries | How it works |
|---|---|---|
stream_wrapper |
fopen(), fread(), file_get_contents(), Symfony\Component\HttpClient\NativeHttpClient |
Replaces the http/https stream wrapper — no source rewriting |
curl |
curl_* functions, Symfony\Component\HttpClient\CurlHttpClient, Guzzle (curl backend) |
Rewrites curl_* calls in loaded PHP source via a stream filter |
soap |
SoapClient |
Rewrites new SoapClient(…) in loaded PHP source via a stream filter |
To enable only specific hooks (e.g. when you know your code only uses curl):
\VCR\VCR::configure()->enableLibraryHooks(['curl']); \VCR\VCR::turnOn();
Available hook names: stream_wrapper, curl, soap.
Record modes
The record mode controls how VCR behaves when a cassette is inserted.
| Mode | Constant | Behaviour |
|---|---|---|
new_episodes |
VCR::MODE_NEW_EPISODES |
Default. Plays back recorded interactions; performs real HTTP for any request that has no recording and records the response. |
once |
VCR::MODE_ONCE |
Plays back recorded interactions. Allows new requests only when the cassette is new (first run). Throws on a miss after that. |
none |
VCR::MODE_NONE |
Read-only. Plays back recorded interactions only. Throws on any request that has no recording. |
all |
VCR::MODE_ALL |
Re-record mode. Never plays back. Always performs the real HTTP request and records the response fresh. The cassette is purged on insert so every run starts clean. |
// Re-record an existing cassette from scratch \VCR\VCR::configure()->setMode(\VCR\VCR::MODE_ALL); \VCR\VCR::turnOn(); \VCR\VCR::insertCassette('my_cassette'); // existing recordings are purged file_get_contents('http://example.com'); // hits network, recorded fresh \VCR\VCR::eject(); \VCR\VCR::turnOff();
Note: A run under
MODE_ALLthat performs no HTTP request leaves an empty cassette — this is inherent to the fresh re-record semantics.
Installation
Simply run the following command:
$ composer require --dev php-vcr/php-vcr
Dependencies
PHP-VCR depends on:
- PHP 8
- Curl extension
- symfony/event-dispatcher
- symfony/yaml
- beberlei/assert
Composer installs all dependencies except extensions like curl.
Run tests
In order to run all tests you need to get development dependencies using composer:
composer install composer test
Changelog
The changelog has moved to the PHP-VCR releases page.
Copyright
Copyright (c) 2013-2023 Adrian Philipp. Released under the terms of the MIT license. See LICENSE for details. Contributors
