pytest-recording


Namepytest-recording JSON
Version 0.13.2 PyPI version JSON
download
home_pageNone
SummaryA pytest plugin that allows you recording of network interactions via VCR.py
upload_time2024-07-09 10:11:07
maintainerNone
docs_urlNone
authorNone
requires_python>=3.7
licenseNone
keywords mock network pytest vcr
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage
            pytest-recording
================

|codecov| |Build| |Version| |Python versions| |License|

A pytest plugin that records network interactions in your tests via VCR.py.

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

⚠️This project is not compatible with `pytest-vcr`, make sure to uninstall before ⚠️


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 block it with ``pytest.mark.block_network`` mark:

.. code:: python

    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:

.. code:: python

    import pytest
    import requests

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

Run ``pytest``:

.. code:: bash

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

.. code:: python

    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:

.. code:: bash

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


Or via `vcr_config` fixture:

.. code:: python

    import pytest

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

Additional resources
--------------------

Looking for more examples? Check out `this article <https://code.kiwi.com/pytest-cassettes-forget-about-mocks-or-live-requests-a9336e1caee6>`_ about ``pytest-recording``.

Contributing
------------

To run the tests:

.. code:: bash

    $ tox -p all

For more information, take a look at `our contributing guide <https://github.com/kiwicom/pytest-recording/blob/master/CONTRIBUTING.rst>`_

Python support
--------------

Pytest-recording supports:

- CPython 3.7, 3.8, 3.9, 3.10, 3.11, and 3.12
- PyPy 7 (3.6)

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.


.. |codecov| image:: https://codecov.io/gh/kiwicom/pytest-recording/branch/master/graph/badge.svg
   :target: https://codecov.io/gh/kiwicom/pytest-recording
.. |Build| image:: https://github.com/kiwicom/pytest-recording/actions/workflows/build.yml/badge.svg
   :target: https://github.com/kiwicom/pytest-recording/actions?query=workflow%3Abuild
.. |Version| image:: https://img.shields.io/pypi/v/pytest-recording.svg
   :target: https://pypi.org/project/pytest-recording/
.. |Python versions| image:: https://img.shields.io/pypi/pyversions/pytest-recording.svg
   :target: https://pypi.org/project/pytest-recording/
.. |License| image:: https://img.shields.io/pypi/l/pytest-recording.svg
   :target: https://opensource.org/licenses/MIT

.. _MIT license: https://opensource.org/licenses/MIT

            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "pytest-recording",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.7",
    "maintainer_email": "Dmitry Dygalo <dmitry@dygalo.dev>",
    "keywords": "mock, network, pytest, vcr",
    "author": null,
    "author_email": "Dmitry Dygalo <dmitry@dygalo.dev>",
    "download_url": "https://files.pythonhosted.org/packages/fe/2a/ea6b8036ae01979eae02d8ad5a7da14dec90d9176b613e49fb8d134c78fc/pytest_recording-0.13.2.tar.gz",
    "platform": null,
    "description": "pytest-recording\n================\n\n|codecov| |Build| |Version| |Python versions| |License|\n\nA pytest plugin that records network interactions in your tests via VCR.py.\n\nFeatures\n--------\n\n- Straightforward ``pytest.mark.vcr``, that reflects ``VCR.use_cassettes`` API;\n- Combining multiple VCR cassettes;\n- Network access blocking;\n- The ``rewrite`` recording mode that rewrites cassettes from scratch.\n\nInstallation\n------------\n\nThis project can be installed via pip:\n\n.. code:: bash\n\n    pip install pytest-recording\n\n\u26a0\ufe0fThis project is not compatible with `pytest-vcr`, make sure to uninstall before \u26a0\ufe0f\n\n\nUsage\n-----\n\n.. code:: python\n\n    import pytest\n    import requests\n\n    # cassettes/{module_name}/test_single.yaml will be used\n    @pytest.mark.vcr\n    def test_single():\n        assert requests.get(\"http://httpbin.org/get\").text == '{\"get\": true}'\n\n    # cassettes/{module_name}/example.yaml will be used\n    @pytest.mark.default_cassette(\"example.yaml\")\n    @pytest.mark.vcr\n    def test_default():\n        assert requests.get(\"http://httpbin.org/get\").text == '{\"get\": true}'\n\n    # these cassettes will be used in addition to the default one\n    @pytest.mark.vcr(\"/path/to/ip.yaml\", \"/path/to/get.yaml\")\n    def test_multiple():\n        assert requests.get(\"http://httpbin.org/get\").text == '{\"get\": true}'\n        assert requests.get(\"http://httpbin.org/ip\").text == '{\"ip\": true}'\n\n    # Make assertions based on the cassette calls/responses:\n    @pytest.mark.vcr\n    def test_call_count(vcr):\n        assert requests.get(\"http://httpbin.org/get\").text == '{\"get\": true}'\n        assert requests.get(\"http://httpbin.org/ip\").text == '{\"ip\": true}'\n        # See https://vcrpy.readthedocs.io/en/latest/advanced.html for more info\n        # about the Cassette object:\n        assert vcr.play_count == 2\n\nRun your tests:\n\n.. code:: bash\n\n    pytest --record-mode=once test_network.py\n\nDefault recording mode\n~~~~~~~~~~~~~~~~~~~~~~\n\n``pytest-recording`` uses the ``none`` VCR recording mode by default to prevent unintentional network requests.\nTo allow them you need to pass a different recording mode (e.g. ``once``) via the ``--record-mode`` CLI option to your test command.\nSee more information about available recording modes in the `official VCR documentation <https://vcrpy.readthedocs.io/en/latest/usage.html#record-modes>`_\n\nConfiguration\n~~~~~~~~~~~~~\n\nYou can provide the recording configuration with the ``vcr_config`` fixture, which could be any scope - ``session``,\n``package``, ``module``, or ``function``. It should return a dictionary that will be passed directly to ``VCR.use_cassettes``\nunder the hood.\n\n.. code:: python\n\n    import pytest\n\n    @pytest.fixture(scope=\"module\")\n    def vcr_config():\n        return {\"filter_headers\": [\"authorization\"]}\n\nFor more granular control you need to pass these keyword arguments to individual ``pytest.mark.vcr`` marks, and in this case\nall arguments will be merged into a single dictionary with the following priority (low -> high):\n\n- ``vcr_config`` fixture\n- all marks from the most broad scope (\"session\") to the most narrow one (\"function\")\n\nExample:\n\n.. code:: python\n\n    import pytest\n\n    pytestmark = [pytest.mark.vcr(ignore_localhost=True)]\n\n    @pytest.fixture(scope=\"module\")\n    def vcr_config():\n        return {\"filter_headers\": [\"authorization\"]}\n\n    @pytest.mark.vcr(filter_headers=[])\n    def test_one():\n        ...\n\n    @pytest.mark.vcr(filter_query_parameters=[\"api_key\"])\n    def test_two():\n        ...\n\nResulting VCR configs for each test:\n\n- ``test_one`` - ``{\"ignore_localhost\": True, \"filter_headers\": []}``\n- ``test_two`` - ``{\"ignore_localhost\": True, \"filter_headers\": [\"authorization\"], \"filter_query_parameters\": [\"api_key\"]}``\n\nYou can get access to the used ``VCR`` instance via ``pytest_recording_configure`` hook. It might be useful for registering\ncustom matchers, persisters, etc.:\n\n.. code:: python\n\n    # conftest.py\n\n    def jurassic_matcher(r1, r2):\n        assert r1.uri == r2.uri and \"JURASSIC PARK\" in r1.body, \\\n            \"required string (JURASSIC PARK) not found in request body\"\n\n    def pytest_recording_configure(config, vcr):\n        vcr.register_matcher(\"jurassic\", jurassic_matcher)\n\nYou can disable the VCR.py integration entirely by passing the ``--disable-recording`` CLI option.\n\nRewrite record mode\n~~~~~~~~~~~~~~~~~~~\n\nIt 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.\n\nHowever, it will rewrite only the default cassette and won't touch extra cassettes.\n\n.. code:: python\n\n    import pytest\n\n    @pytest.fixture(scope=\"module\")\n    def vcr_config():\n        return {\"record_mode\": \"rewrite\"}\n\nOr via command-line option:\n\n.. code:: bash\n\n    $ pytest --record-mode=rewrite tests/\n\nBlocking network access\n~~~~~~~~~~~~~~~~~~~~~~~\n\nTo have more confidence that your tests will not go over the wire, you can block it with ``pytest.mark.block_network`` mark:\n\n.. code:: python\n\n    import pytest\n    import requests\n\n    @pytest.mark.block_network\n    def test_multiple():\n        assert requests.get(\"http://httpbin.org/get\").text == '{\"get\": true}'\n\n    ...\n    # in case of access\n    RuntimeError: Network is disabled\n\nBesides marks, the network access could be blocked globally with ``--block-network`` command-line option.\n\nHowever, if VCR.py recording is enabled, the network is not blocked for tests with ``pytest.mark.vcr``.\n\nExample:\n\n.. code:: python\n\n    import pytest\n    import requests\n\n    @pytest.mark.vcr\n    def test_multiple():\n        assert requests.get(\"http://httpbin.org/get\").text == '{\"get\": true}'\n\nRun ``pytest``:\n\n.. code:: bash\n\n    $ pytest --record-mode=once --block-network tests/\n\nThe network blocking feature supports ``socket``-based transports and ``pycurl``.\n\nIt is possible to allow access to specified hosts during network blocking:\n\n.. code:: python\n\n    import pytest\n    import requests\n\n    @pytest.mark.block_network(allowed_hosts=[\"httpbin.*\"])\n    def test_access():\n        assert requests.get(\"http://httpbin.org/get\").text == '{\"get\": true}'\n        with pytest.raises(RuntimeError, match=r\"^Network is disabled$\"):\n            requests.get(\"http://example.com\")\n\nOr via command-line option:\n\n.. code:: bash\n\n    $ pytest --record-mode=once --block-network --allowed-hosts=httpbin.*,localhost tests/\n\n\nOr via `vcr_config` fixture:\n\n.. code:: python\n\n    import pytest\n\n    @pytest.fixture(autouse=True)\n    def vcr_config():\n        return {\"allowed_hosts\": [\"httpbin.*\"]}\n\nAdditional resources\n--------------------\n\nLooking for more examples? Check out `this article <https://code.kiwi.com/pytest-cassettes-forget-about-mocks-or-live-requests-a9336e1caee6>`_ about ``pytest-recording``.\n\nContributing\n------------\n\nTo run the tests:\n\n.. code:: bash\n\n    $ tox -p all\n\nFor more information, take a look at `our contributing guide <https://github.com/kiwicom/pytest-recording/blob/master/CONTRIBUTING.rst>`_\n\nPython support\n--------------\n\nPytest-recording supports:\n\n- CPython 3.7, 3.8, 3.9, 3.10, 3.11, and 3.12\n- PyPy 7 (3.6)\n\nLicense\n-------\n\nThe 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.\n\n\n.. |codecov| image:: https://codecov.io/gh/kiwicom/pytest-recording/branch/master/graph/badge.svg\n   :target: https://codecov.io/gh/kiwicom/pytest-recording\n.. |Build| image:: https://github.com/kiwicom/pytest-recording/actions/workflows/build.yml/badge.svg\n   :target: https://github.com/kiwicom/pytest-recording/actions?query=workflow%3Abuild\n.. |Version| image:: https://img.shields.io/pypi/v/pytest-recording.svg\n   :target: https://pypi.org/project/pytest-recording/\n.. |Python versions| image:: https://img.shields.io/pypi/pyversions/pytest-recording.svg\n   :target: https://pypi.org/project/pytest-recording/\n.. |License| image:: https://img.shields.io/pypi/l/pytest-recording.svg\n   :target: https://opensource.org/licenses/MIT\n\n.. _MIT license: https://opensource.org/licenses/MIT\n",
    "bugtrack_url": null,
    "license": null,
    "summary": "A pytest plugin that allows you recording of network interactions via VCR.py",
    "version": "0.13.2",
    "project_urls": {
        "Bug Tracker": "https://github.com/kiwicom/pytest-recording/issues",
        "Changelog": "https://github.com/kiwicom/pytest-recording/blob/master/docs/changelog.rst",
        "Documentation": "https://github.com/kiwicom/pytest-recording",
        "Source Code": "https://github.com/kiwicom/pytest-recording"
    },
    "split_keywords": [
        "mock",
        " network",
        " pytest",
        " vcr"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "72528e67a969e9fad3fa5ec4eab9f2a7348ff04692065c7deda21d76e9112703",
                "md5": "c3364bb6ae8edcfa058331d9e6b49e24",
                "sha256": "3820fe5743d1ac46e807989e11d073cb776a60bdc544cf43ebca454051b22d13"
            },
            "downloads": -1,
            "filename": "pytest_recording-0.13.2-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "c3364bb6ae8edcfa058331d9e6b49e24",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.7",
            "size": 12783,
            "upload_time": "2024-07-09T10:11:05",
            "upload_time_iso_8601": "2024-07-09T10:11:05.322573Z",
            "url": "https://files.pythonhosted.org/packages/72/52/8e67a969e9fad3fa5ec4eab9f2a7348ff04692065c7deda21d76e9112703/pytest_recording-0.13.2-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "fe2aea6b8036ae01979eae02d8ad5a7da14dec90d9176b613e49fb8d134c78fc",
                "md5": "171dd5c6dbad3d5e3ea2c8a150c1625f",
                "sha256": "000c3babbb466681457fd65b723427c1779a0c6c17d9e381c3142a701e124877"
            },
            "downloads": -1,
            "filename": "pytest_recording-0.13.2.tar.gz",
            "has_sig": false,
            "md5_digest": "171dd5c6dbad3d5e3ea2c8a150c1625f",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.7",
            "size": 25270,
            "upload_time": "2024-07-09T10:11:07",
            "upload_time_iso_8601": "2024-07-09T10:11:07.353025Z",
            "url": "https://files.pythonhosted.org/packages/fe/2a/ea6b8036ae01979eae02d8ad5a7da14dec90d9176b613e49fb8d134c78fc/pytest_recording-0.13.2.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-07-09 10:11:07",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "kiwicom",
    "github_project": "pytest-recording",
    "travis_ci": false,
    "coveralls": true,
    "github_actions": true,
    "tox": true,
    "lcname": "pytest-recording"
}
        
Elapsed time: 4.53815s