php-vcr/php-vcr

Record your test suite's HTTP interactions and replay them during future test runs for fast, deterministic, accurate tests.

Maintainers

Package info

github.com/php-vcr/php-vcr

pkg:composer/php-vcr/php-vcr

Transparency log

Statistics

Installs: 3 226 414

Dependents: 143

Suggesters: 0

Stars: 1 208

Open Issues: 28

1.10.0 2026-07-05 22:50 UTC

README

PHP-VCR

Continuous Integration Code Coverage Scrutinizer Quality Score

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_ALL that 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:

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.

Old changelog entries

Copyright

Copyright (c) 2013-2023 Adrian Philipp. Released under the terms of the MIT license. See LICENSE for details. Contributors