Skip to main content

A pytest plugin powered by VCR.py to record and replay HTTP traffic

Project description

codecov Build Version Python versions License

A pytest plugin powered by VCR.py to record and replay HTTP traffic.

Features

  • Straightforward pytest.mark.vcr, that reflects VCR.use_cassettes API;

  • Combining multiple VCR cassettes;

  • Network access blocking;

  • The rewrite recording mode that rewrites cassettes from scratch.

Installation

This project can be installed via pip:

   pip install pytest-recording

⚠️ Incompatible with ``pytest-vcr``  please uninstall ``pytest-vcr`` before use. ⚠️

Usage

import pytest
import requests

# cassettes/{module_name}/test_single.yaml will be used
@pytest.mark.vcr
def test_single():
    assert requests.get("http://httpbin.org/get").text == '{"get": true}'

# cassettes/{module_name}/example.yaml will be used
@pytest.mark.default_cassette("example.yaml")
@pytest.mark.vcr
def test_default():
    assert requests.get("http://httpbin.org/get").text == '{"get": true}'

# these cassettes will be used in addition to the default one
@pytest.mark.vcr("/path/to/ip.yaml", "/path/to/get.yaml")
def test_multiple():
    assert requests.get("http://httpbin.org/get").text == '{"get": true}'
    assert requests.get("http://httpbin.org/ip").text == '{"ip": true}'

# Make assertions based on the cassette calls/responses:
@pytest.mark.vcr
def test_call_count(vcr):
    assert requests.get("http://httpbin.org/get").text == '{"get": true}'
    assert requests.get("http://httpbin.org/ip").text == '{"ip": true}'
    # See https://vcrpy.readthedocs.io/en/latest/advanced.html for more info
    # about the Cassette object:
    assert vcr.play_count == 2

Run your tests:

pytest --record-mode=once test_network.py

Default recording mode

pytest-recording uses the none VCR recording mode by default to prevent unintentional network requests. To allow them you need to pass a different recording mode (e.g. once) via the --record-mode CLI option to your test command. See more information about available recording modes in the official VCR documentation

Configuration

You can provide the recording configuration with the vcr_config fixture, which could be any scope - session, package, module, or function. It should return a dictionary that will be passed directly to VCR.use_cassettes under the hood.

import pytest

@pytest.fixture(scope="module")
def vcr_config():
    return {"filter_headers": ["authorization"]}

For more granular control you need to pass these keyword arguments to individual pytest.mark.vcr marks, and in this case all arguments will be merged into a single dictionary with the following priority (low -> high):

  • vcr_config fixture

  • all marks from the most broad scope (“session”) to the most narrow one (“function”)

Example:

import pytest

pytestmark = [pytest.mark.vcr(ignore_localhost=True)]

@pytest.fixture(scope="module")
def vcr_config():
    return {"filter_headers": ["authorization"]}

@pytest.mark.vcr(filter_headers=[])
def test_one():
    ...

@pytest.mark.vcr(filter_query_parameters=["api_key"])
def test_two():
    ...

Resulting VCR configs for each test:

  • test_one - {"ignore_localhost": True, "filter_headers": []}

  • test_two - {"ignore_localhost": True, "filter_headers": ["authorization"], "filter_query_parameters": ["api_key"]}

You can get access to the used VCR instance via pytest_recording_configure hook. It might be useful for registering custom matchers, persisters, etc.:

# conftest.py

def jurassic_matcher(r1, r2):
    assert r1.uri == r2.uri and "JURASSIC PARK" in r1.body, \
        "required string (JURASSIC PARK) not found in request body"

def pytest_recording_configure(config, vcr):
    vcr.register_matcher("jurassic", jurassic_matcher)

You can disable the VCR.py integration entirely by passing the --disable-recording CLI option.

Rewrite record mode

It is possible to rewrite a cassette from scratch and not extend it with new entries as it works now with the all record mode from VCR.py.

However, it will rewrite only the default cassette and won’t touch extra cassettes.

import pytest

@pytest.fixture(scope="module")
def vcr_config():
    return {"record_mode": "rewrite"}

Or via command-line option:

$ pytest --record-mode=rewrite tests/

Blocking network access

To have more confidence that your tests will not go over the wire, you can block it with pytest.mark.block_network mark:

import pytest
import requests

@pytest.mark.block_network
def test_multiple():
    assert requests.get("http://httpbin.org/get").text == '{"get": true}'

...
# in case of access
RuntimeError: Network is disabled

Besides marks, the network access could be blocked globally with --block-network command-line option.

However, if VCR.py recording is enabled, the network is not blocked for tests with pytest.mark.vcr.

Example:

import pytest
import requests

@pytest.mark.vcr
def test_multiple():
    assert requests.get("http://httpbin.org/get").text == '{"get": true}'

Run pytest:

$ pytest --record-mode=once --block-network tests/

The network blocking feature supports socket-based transports and pycurl.

It is possible to allow access to specified hosts during network blocking:

import pytest
import requests

@pytest.mark.block_network(allowed_hosts=["httpbin.*"])
def test_access():
    assert requests.get("http://httpbin.org/get").text == '{"get": true}'
    with pytest.raises(RuntimeError, match=r"^Network is disabled$"):
        requests.get("http://example.com")

Or via command-line option:

$ pytest --record-mode=once --block-network --allowed-hosts=httpbin.*,localhost tests/

Or via vcr_config fixture:

import pytest

@pytest.fixture(autouse=True)
def vcr_config():
    return {"allowed_hosts": ["httpbin.*"]}

Additional resources

Looking for more examples? Check out this article about pytest-recording.

Contributing

To run the tests:

$ tox -p all

For more information, take a look at our contributing guide

Test Isolation for Package Maintainers

When running pytest-based tests in a packaging environment, globally installed plugins can break test suites by injecting unexpected hooks or fixtures (e.g. pytest-pretty) that your code isn’t designed for.

To guarantee a clean, reproducible test run:

export PYTEST_DISABLE_PLUGIN_AUTOLOAD=1
export PYTEST_PLUGINS=pytest_httpbin.plugin,pytest_mock,pytest_recording.plugin
  • PYTEST_DISABLE_PLUGIN_AUTOLOAD Disables loading of any plugins via setuptools entry-points; only those you explicitly list will be activated.

  • PYTEST_PLUGINS Comma-separated list of plugin modules pytest should load (the core plugin manager still discovers builtin plugins and conftest.py).

Include these exports in your package’s build or CI script so that system-wide pytest plugins (e.g. linting, formatting, or unrelated test helpers) cannot interfere with your tests.

Python support

Pytest-recording supports:

  • CPython 3.9, 3.10, 3.11, 3.12, and 3.13

  • PyPy 7.3 (3.10)

License

The code in this project is licensed under MIT license. By contributing to pytest-recording, you agree that your contributions will be licensed under its MIT license.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pytest_recording-0.13.3.tar.gz (26.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pytest_recording-0.13.3-py3-none-any.whl (13.6 kB view details)

Uploaded Python 3

File details

Details for the file pytest_recording-0.13.3.tar.gz.

File metadata

  • Download URL: pytest_recording-0.13.3.tar.gz
  • Upload date:
  • Size: 26.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.12.9

File hashes

Hashes for pytest_recording-0.13.3.tar.gz
Algorithm Hash digest
SHA256 dd018421a956ecc45f112c051b1e323b40d029879b1062853df45b05c6098310
MD5 fb3d92cbdc91c7edb07bf09d92665766
BLAKE2b-256 7181f68b5ff9decda92b4e3808295606bfdfa7048c78386eeeb2357c09b8a4a2

See more details on using hashes here.

File details

Details for the file pytest_recording-0.13.3-py3-none-any.whl.

File metadata

File hashes

Hashes for pytest_recording-0.13.3-py3-none-any.whl
Algorithm Hash digest
SHA256 d4d5c5b50aea0db25459116633b82673e646ea9f1575cf8d3dbc03c49e93e1d8
MD5 a590d4c0f087009fabf7c540235e7442
BLAKE2b-256 010eedcfb71fc77ab31008fc3b6e6afcb324b844a3a0dc990d24ca19d48d7261

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page