# pytest-recording

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

- **URL**: https://www.freshcrate.ai/projects/pytest-recording
- **Author**: pypi
- **Category**: Frameworks
- **Latest version**: `0.13.4` (2026-04-21)
- **License**: Unknown
- **Source**: https://github.com/kiwicom/pytest-recording/issues
- **Homepage**: https://pypi.org/project/pytest-recording/
- **Language**: Python
- **GitHub**: 605 stars, 45 forks
- **Registry**: pypi (`pytest-recording`)
- **Tags**: `mock`, `network`, `pypi`, `pytest`, `vcr`

## Description

pytest-recording
================

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

.. code:: bash

    pip install pytest-recording

⚠️ Incompatibility Warning

  If you have ``pytest-vcr`` installed, please uninstall it before using ``pytest-recording``, as the two plugins are incompatible.

Usage
-----

.. code:: python

    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:

.. code:: bash

    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 <https://vcrpy.readthedocs.io/en/latest/usage.html#record-modes>`_

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.

.. code:: python

    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:

.. code:: python

    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.:

.. code:: python

    # 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.

.. code:: python

    import pytest

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

Or via command-line option:

.. code:: bash

    $ pytest --record-mode=rewrite tests/

Blocking network access
~~~~~~~~~~~~~~~~~~~~~~~

To have more confidence that your tests will not go over the wire, you can

## Recent releases

| Version | Date | Urgency | Changes |
| --- | --- | --- | --- |
| `0.13.4` | 2026-04-21 | Low | Imported from PyPI (0.13.4) |
| `v0.13.4` | 2025-05-08 | Low | ### Fixed  - `AttributeError` on Windows. #174 |
| `v0.13.4` | 2025-05-08 | Low | ### Fixed  - `AttributeError` on Windows. #174 |
| `v0.13.4` | 2025-05-08 | Low | ### Fixed  - `AttributeError` on Windows. #174 |
| `v0.13.4` | 2025-05-08 | Low | ### Fixed  - `AttributeError` on Windows. #174 |
| `v0.13.4` | 2025-05-08 | Low | ### Fixed  - `AttributeError` on Windows. #174 |
| `v0.13.4` | 2025-05-08 | Low | ### Fixed  - `AttributeError` on Windows. #174 |
| `v0.13.4` | 2025-05-08 | Low | ### Fixed  - `AttributeError` on Windows. #174 |
| `v0.13.4` | 2025-05-08 | Low | ### Fixed  - `AttributeError` on Windows. #174 |
| `v0.13.4` | 2025-05-08 | Low | ### Fixed  - `AttributeError` on Windows. #174 |

## Citation

- HTML: https://www.freshcrate.ai/projects/pytest-recording
- Markdown: https://www.freshcrate.ai/projects/pytest-recording.md
- Dependencies JSON: https://www.freshcrate.ai/api/projects/pytest-recording/deps

_Generated by freshcrate.ai. Indexes pypi releases for AI-agent ecosystem packages._
