Automatically mock your HTTP interactions to simplify and speed up testing
npx @tessl/cli install tessl/pypi-vcrpy@7.0.0A Python library that records HTTP interactions during test execution and replays them in subsequent runs, enabling completely offline, deterministic, and fast tests. VCR.py automatically intercepts HTTP requests and responses through supported libraries and serializes them to cassette files, eliminating actual network traffic while maintaining test reliability.
pip install vcrpyimport vcrCommon patterns:
# Use default VCR instance
from vcr import use_cassette
# Create custom VCR instance
from vcr import VCR
# Access record modes
from vcr import mode # or vcr.mode
# For unittest integration
from vcr.unittest import VCRTestCase, VCRMixinimport vcr
import requests
# Using decorator
@vcr.use_cassette('fixtures/vcr_cassettes/synopsis.yaml')
def test_synopsis():
response = requests.get('http://httpbin.org/json')
assert response.status_code == 200
# Using context manager
def test_with_context():
with vcr.use_cassette('fixtures/vcr_cassettes/synopsis.yaml'):
response = requests.get('http://httpbin.org/json')
assert response.status_code == 200
# Custom VCR configuration
my_vcr = vcr.VCR(
serializer='json',
record_mode='once',
filter_headers=['authorization'],
match_on=['method', 'scheme', 'host', 'port', 'path', 'query']
)
@my_vcr.use_cassette('custom_cassette.json')
def test_with_custom_vcr():
response = requests.get('http://api.example.com/data')
assert response.status_code == 200VCR.py operates through HTTP library patching and cassette-based recording:
The library supports multiple record modes, serialization formats, and extensive customization options for different testing scenarios.
Central configuration and context management for HTTP recording and playback, including cassette management, record modes, and extensive customization options.
class VCR:
def __init__(
self,
path_transformer=None,
before_record_request=None,
custom_patches=(),
filter_query_parameters=(),
ignore_hosts=(),
record_mode=RecordMode.ONCE,
ignore_localhost=False,
filter_headers=(),
before_record_response=None,
filter_post_data_parameters=(),
match_on=("method", "scheme", "host", "port", "path", "query"),
before_record=None,
inject_cassette=False,
serializer="yaml",
cassette_library_dir=None,
func_path_generator=None,
decode_compressed_response=False,
record_on_exception=True,
): ...
def use_cassette(self, path=None, **kwargs): ...
def use_cassette(path=None, **kwargs): ...Recording behavior configuration that determines when HTTP interactions are recorded versus replayed from existing cassettes.
class RecordMode(str, Enum):
ALL = "all"
ANY = "any"
NEW_EPISODES = "new_episodes"
NONE = "none"
ONCE = "once"
# Alias for RecordMode
mode = RecordModeHTTP request and response representation with case-insensitive headers, body processing, and URI parsing capabilities.
class Request:
def __init__(self, method: str, uri: str, body, headers): ...
@property
def headers(self) -> HeadersDict: ...
@property
def body(self): ...
@property
def method(self) -> str: ...
@property
def uri(self) -> str: ...
@property
def scheme(self) -> str: ...
@property
def host(self) -> str: ...
@property
def port(self) -> int: ...
@property
def path(self) -> str: ...
@property
def query(self) -> str: ...
class HeadersDict(dict):
"""Case-insensitive dictionary for HTTP headers"""Request and Response Processing
Functions for determining if recorded requests match incoming requests, supporting multiple matching strategies for different use cases.
def method(r1: Request, r2: Request): ...
def uri(r1: Request, r2: Request): ...
def host(r1: Request, r2: Request): ...
def scheme(r1: Request, r2: Request): ...
def port(r1: Request, r2: Request): ...
def path(r1: Request, r2: Request): ...
def query(r1: Request, r2: Request): ...
def headers(r1: Request, r2: Request): ...
def raw_body(r1: Request, r2: Request): ...
def body(r1: Request, r2: Request): ...
def requests_match(r1: Request, r2: Request, matchers): ...
def get_matchers_results(r1: Request, r2: Request, matchers): ...Functions for removing or replacing sensitive data in requests and responses before recording to cassettes.
def replace_headers(request: Request, replacements: list): ...
def remove_headers(request: Request, headers_to_remove: list): ...
def replace_query_parameters(request: Request, replacements: list): ...
def replace_post_data_parameters(request: Request, replacements: list): ...
def decode_response(response): ...Integration classes for unittest framework providing automatic cassette management and VCR configuration for test cases.
class VCRMixin:
vcr_enabled: bool = True
def setUp(self): ...
def _get_vcr(self, **kwargs) -> VCR: ...
def _get_vcr_kwargs(self, **kwargs) -> dict: ...
def _get_cassette_library_dir(self) -> str: ...
def _get_cassette_name(self) -> str: ...
class VCRTestCase(VCRMixin, unittest.TestCase):
passException classes for handling VCR-specific errors during recording and playback operations.
class CannotOverwriteExistingCassetteException(Exception):
def __init__(self, cassette, failed_request): ...
cassette: Cassette
failed_request: Request
class UnhandledHTTPRequestError(KeyError):
"""Raised when a cassette does not contain the request we want."""Cassette serialization and deserialization support for YAML and JSON formats with extensible serializer registration.
# YAML Serializer
def deserialize(cassette_string: str) -> dict: ...
def serialize(cassette_dict: dict) -> str: ...
# JSON Serializer
def deserialize(cassette_string: str) -> dict: ...
def serialize(cassette_dict: dict) -> str: ...from typing import Callable, Any, Optional, Union, Dict, List, Tuple
from enum import Enum
from pathlib import Path
# Configuration types
PathTransformer = Callable[[str], str]
FilterFunction = Callable[[Any], Any]
MatcherFunction = Callable[[Request, Request], None] # Raises AssertionError if no match
SerializerModule = Any # Module with serialize/deserialize functions
# Request/Response types
Headers = Union[Dict[str, str], HeadersDict]
Body = Union[str, bytes, Any] # file-like objects or iterables also supported