Network calls in tests are the number-one source of non-determinism: rate limits, timeouts, slow CI runners, and API downtime all make otherwise-correct tests fail randomly. The VCR (Video Cassette Recorder) pattern solves this: you record a real HTTP interaction once, save it to a "cassette" file, and replay that file in every subsequent test run โ no live network required.
This guide walks through the VCR cassette workflow in APIGhost โ an open-source mock server for OpenAPI specs that has first-class VCR recording built in alongside spec-driven faking.
Why VCR cassettes instead of patching?
The traditional Python approach to mocking HTTP is unittest.mock.patch or the responses library. Both work, but they require you to handcraft response bodies โ which drift from reality as APIs evolve and are tedious to maintain for deeply nested JSON payloads.
| Approach | Pros | Cons |
|---|---|---|
unittest.mock.patch | No dependencies, familiar | Manual JSON; drifts from real API silently |
responses library | URL-pattern matching | Still hand-authored bodies; no serialisation to disk |
vcrpy | Real recordings | Coupled to underlying HTTP lib; cassettes can be large/noisy |
| APIGhost VCR | Recorded interactions; integrates with the APIGhost mock server | Requires a running APIGhost process |
APIGhost's README documents VCR recording and deterministic replay alongside spec-driven mock-server generation. Choose the workflow that fits your test suite, then review recorded data before committing it.
Installation
APIGhost is MIT-licensed. Its README documents a source install and a Homebrew installation path:
# pip โ documented source install
pip install git+https://github.com/Coding-Dev-Tools/apighost.git
# Homebrew (macOS / Linux)
brew tap Coding-Dev-Tools/homebrew-tap
brew install apighost
Verify the install:
apighost --version
Note: pip install apighost (bare, no --index-url) will fail โ the package is not on public PyPI. Use one of the commands above.
The record โ replay workflow
There are three steps:
- Record โ use APIGhost's record command to save interactions to a cassette.
- Commit the cassette alongside your test code.
- Replay โ in CI (or locally), start APIGhost in replay mode; it serves the saved cassette without touching the network.
Step 1 โ Record a cassette
Point APIGhost at an OpenAPI spec and write the recorded output to a cassette path:
apighost record petstore.yaml --output fixtures/petstore-cassette.json
Use only non-sensitive test data when recording. Before committing any cassette, inspect its contents and remove credentials or personal data.
Step 2 โ Inspect and commit the cassette
Open fixtures/petstore-cassette.json to review what was captured before committing it. A cassette entry looks like:
{
"id": "get_pets_001",
"request": {
"method": "GET",
"path": "/v1/pets",
"headers": {"Accept": "application/json"}
},
"response": {
"status": 200,
"headers": {"Content-Type": "application/json"},
"body": [
{"id": 1, "name": "Noodle", "tag": "cat"},
{"id": 2, "name": "Biscuit"}
]
},
"schema_operation": "GET /v1/pets",
"recorded_at": "2026-07-11T08:12:33Z"
}
Scrub any credentials or personal data from the cassette before committing it:
git add fixtures/petstore-cassette.json
git commit -m "test: add petstore VCR cassette"
Step 3 โ Replay in pytest
Start APIGhost in replay mode as a pytest fixture so it boots before your tests and shuts down after:
# conftest.py
import subprocess
import time
import pytest
@pytest.fixture(scope="session", autouse=True)
def apighost_replay():
"""Start APIGhost in VCR replay mode for the test session."""
proc = subprocess.Popen(
[
"apighost", "replay", "fixtures/petstore-cassette.json",
"-p", "4000",
],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
)
time.sleep(1) # brief wait for server to bind
yield proc
proc.terminate()
proc.wait()
Now point your test HTTP client at http://localhost:4000 โ no live network is touched:
# test_pets_api.py
import httpx
BASE = "http://localhost:4000"
def test_list_pets():
r = httpx.get(f"{BASE}/v1/pets")
assert r.status_code == 200
data = r.json()
assert isinstance(data, list)
assert data[0]["name"] == "Noodle" # matches our cassette
def test_get_single_pet():
r = httpx.get(f"{BASE}/v1/pets/42")
assert r.status_code == 200
pet = r.json()
assert "id" in pet
def test_create_pet():
r = httpx.post(f"{BASE}/v1/pets", json={"name": "Pretzel", "tag": "dog"})
assert r.status_code == 201
Run the suite:
pytest -v
# ===== 3 passed in 0.4s =====
No network calls. Deterministic. Fast.
Keeping cassettes fresh
APIs change. Here's a low-friction refresh workflow:
- Delete (or rename) the stale cassette file.
- Re-run the record step against the live API.
- Review the diff with
git diff fixtures/petstore-cassette.json. - Update assertions in your tests that depended on changed fields.
- Commit the new cassette.
Reviewing cassette diffs alongside test changes helps make recorded behavior explicit before you update a suite.
CI integration (GitHub Actions example)
# .github/workflows/test.yml (excerpt)
steps:
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with: {python-version: "3.12"}
- name: Install dependencies
run: |
pip install git+https://github.com/Coding-Dev-Tools/apighost.git
pip install httpx pytest
- name: Run tests (VCR replay โ no live network)
run: pytest -v
# apighost replay starts automatically via conftest.py fixture
No secrets needed, no external API calls, no flakiness from rate limits.
Honesty note: cassettes record real response data. Never commit cassettes that contain production PII or credentials. Review the cassette file before git add.
Pricing
- Unlimited local use
- 100 requests/session
- Everything in Free
- Unlimited requests
- VCR cassettes
- CI/CD integration
- All Coding-Dev-Tools tools under one license
Check the README for current feature and plan details before choosing a tier; the documented Free plan includes unlimited local use with a 100-request session limit.
Ready to eliminate flaky network tests? APIGhost is free to install and use locally.
View APIGhost on GitHub โRelated guides
- Using APIGhost as a pytest mock API server โ spec-driven faking without cassettes
- OpenAPI mock server quickstart
- APIGhost getting started guide
APIGhost is MIT-licensed open-source software. Claims about features and pricing are sourced from the official README (verified 2026-07-19). This site is maintained by the Coding Dev Tools team.