Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

System Context

The C4 model describes a system at four zoom levels. This page is level 1: what sits around http-vcr and who talks to whom. Containers opens the test process up, and Components opens the library up.

One thing to keep in mind at every level: http-vcr is a library, not a service. Nothing here is a running process you deploy. The boxes are the pieces of a test run, and the “deployment” is composer require --dev.

graph TB
    dev["<b>Developer</b><br/><span>Person</span><br/><br/>Writes tests, records<br/>cassettes on their machine"]
    ci["<b>CI Pipeline</b><br/><span>Person / automation</span><br/><br/>Runs the suite with no<br/>network and no credentials"]

    subgraph scope[" "]
        suite["<b>Test Suite</b><br/><span>Software System — PHP</span><br/><br/>The project's tests, with http-vcr<br/>decorating the HTTP client the<br/>code under test already uses"]
    end

    api["<b>Third-party HTTP API</b><br/><span>External System</span><br/><br/>Shopify, Stripe, Zendesk…<br/>Reached on the recording run only"]
    repo["<b>Version Control</b><br/><span>External System</span><br/><br/>Cassettes are committed<br/>next to the tests"]

    dev -->|"runs the suite,<br/>records the first time"| suite
    ci -->|"runs the suite,<br/>replay only"| suite
    suite -->|"HTTPS — first run only,<br/>with real credentials"| api
    suite -->|"reads and writes<br/>cassette files"| repo
    dev -->|"reviews cassette diffs<br/>in code review"| repo

    classDef person fill:#08427b,stroke:#052e56,color:#ffffff
    classDef system fill:#1168bd,stroke:#0b4884,color:#ffffff
    classDef external fill:#999999,stroke:#6b6b6b,color:#ffffff
    classDef boundary fill:none,stroke:#444444,stroke-dasharray:5 5,color:#888888

    class dev,ci person
    class suite system
    class api,repo external
    class scope boundary

What the picture is claiming

The API is reached exactly once per cassette. The arrow from the suite to the third-party API is dashed in spirit: it carries traffic on the run that records, and nothing on every run after that. That is the whole point of the library, and it is also why the arrow from CI to the API does not exist — recording is refused on CI so that a missing cassette fails loudly instead of quietly spending real API quota from a build agent.

Cassettes are source, not cache. They are committed, reviewed, and diffed like any other fixture. This is why the format is JSON by default and why secrets are redacted before the file is written rather than after — a cassette that reached disk with a live token in it is already a credential leak in the repository’s history.

There is no process-wide state. http-vcr does not install a stream wrapper, patch curl, or register anything global; it decorates one PSR-18 client instance. Two VcrClient objects in one test run do not interfere, and code that was never handed a decorated client keeps reaching the network exactly as before.

Actors

ActorWhat they doWhat they must have
DeveloperRuns the suite locally, records the cassette the first time a test needs one, commits itReal API credentials in the environment, network access
CI pipelineRuns the same suite in replayNeither. If a cassette is missing, the run fails rather than reaching out

The split between those two rows is a rule the library enforces, not a convention it suggests. See Record Modes for how the decision is made and how to override it in either direction.