responses

repository·master·Indexed 26 days ago

https://github.com/getsentry/responses

A utility library used to mock the Python requests library. It allows developers to intercept HTTP requests and return predefined responses during testing to prevent actual network calls. It features a @responses.activate decorator, context manager support via RequestsMock, and various matchers for validating JSON, URL-encoded data, query parameters, headers, and multipart/form-data.

Tokens
16.4K
Snippets
51
Records
58
Agent score
38%

What's inside responses

  1. Use responses as a context manager

    master

    If you don't want to decorate the entire function, use responses.RequestsMock() as a context manager. Requests made inside the with block are mocked, while requests made outside the block will hit the real server.

    import responses
    import requests
    
    def test_my_api():
        with responses.RequestsMock() as rsps:
            rsps.add(
                responses.GET,
                "http://twitter.com/api/1/foobar",
                body="{}",
                status=200,
                content_type="application/json",
            )
            resp = requests.get("http://twitter.com/api/1/foobar")
            assert resp.status_code == 200
    
        # Outside the context manager, requests hit the real server
        resp = requests.get("http://twitter.com/api/1/foobar")
        # This will likely return a 404 from the real server
  2. Validate urllib3 Retry mechanisms

    master

    To test urllib3 retry logic (like max_retries), you must use the OrderedRegistry. This ensures that multiple registered responses for the same URL are returned in the specific order they were added, allowing the retry logic to progress through different status codes (e.g., 500, 500, 200).

    from responses import registries
    
    @responses.activate(registry=registries.OrderedRegistry)
    def test_max_retries():
        url = "https://example.com"
        responses.get(url, body="Error", status=500)
        responses.get(url, body="Error", status=500)
        responses.get(url, body="OK", status=200)
    
        # Use a requests Session with Retry adapter
        session = requests.Session()
        # ... configure adapter ...
        resp = session.get(url)
        assert resp.status_code == 200
  3. Basic usage of Responses

    master

    To mock requests, use the @responses.activate decorator on your test functions. You can register responses using a responses.Response object or by passing arguments directly to responses.add().

    If a request is made to a URL that does not match any registered response, responses will raise a requests.exceptions.ConnectionError.

    import responses
    import requests
    from requests.exceptions import ConnectionError
    import pytest
    
    @responses.activate
    def test_simple():
        # Register via 'Response' object
        rsp1 = responses.Response(
            method="PUT",
            url="http://example.com",
        )
        responses.add(rsp1)
    
        # Register via direct arguments
        responses.add(
            responses.GET,
            "http://twitter.com/api/1/foobar",
            json={"error": "not found"},
            status=404,
        )
    
        resp = requests.get("http://twitter.com/api/1/foobar")
        assert resp.json() == {"error": "not found"}
        assert resp.status_code == 404
    
    @responses.activate
    def test_no_match():
        with pytest.raises(ConnectionError):
            requests.get("http://twitter.com/api/1/foobar")
  4. Mock requests using the @responses.activate decorator

    master

    The core way to use responses is to wrap your test function with the @responses.activate decorator. This intercepts all calls made via the requests library within that function.

    You can register responses in two ways:

    1. By passing a responses.Response object to responses.add().
    2. By passing arguments directly to responses.add().

    If a request is made to a URL that has not been registered, responses will raise a requests.exceptions.ConnectionError.

    import responses
    import requests
    from requests.exceptions import ConnectionError
    import pytest
    
    @responses.activate
    def test_simple():
        # Registration via Response object
        rsp1 = responses.Response(
            method="PUT",
            url="http://example.com",
        )
        responses.add(rsp1)
    
        # Registration via direct arguments
        responses.add(
            responses.GET,
            "http://twitter.com/api/1/foobar",
            json={"error": "not found"},
            status=404,
        )
    
        resp = requests.get("http://twitter.com/api/1/foobar")
        assert resp.json() == {"error": "not found"}
        assert resp.status_code == 404
    
    @responses.activate
    def test_unregistered_url():
        with pytest.raises(ConnectionError):
            requests.get("http://twitter.com/api/1/unregistered")
  5. Verify request call data

    master

    The Request object contains a calls list. Each element in this list corresponds to a Call object in the global Registry.calls list. This is particularly useful in multi-threaded applications where the order of requests might not be guaranteed, allowing you to verify the correctness of individual calls by checking if they exist within the global registry.

    @responses.activate
    def test_assert_calls_on_resp():
        rsp1 = responses.patch("http://www.foo.bar/1/", status=200)
        # ... perform requests ...
        assert rsp1.call_count == 1
        assert rsp1.calls[0] in responses.calls
        assert rsp1.calls[0].response.status_code == 200
  6. Integrate Responses with pytest

    master

    To use responses as a fixture in pytest, install the pytest-responses package:

    pip install pytest-responses

    Once installed, you can inject the responses fixture directly into your test functions.

    import pytest_responses
    
    def test_api(responses):
        responses.get(
            "http://twitter.com/api/1/foobar",
            body="{}",
            status=200,
            content_type="application/json",
        )
        resp = requests.get("http://twitter.com/api/1/foobar")
        assert resp.status_code == 200
  7. Use Responses as a pytest fixture

    master

    To use responses as a fixture in pytest, install the pytest-responses package:

    pip install pytest-responses

    Then, you can access the responses object directly in your test functions.

    import pytest_responses
    
    def test_api(responses):
        responses.get(
            "http://twitter.com/api/1/foobar",
            body="{}",
            status=200,
            content_type="application/json",
        )
        resp = requests.get("http://twitter.com/api/1/foobar")
        assert resp.status_code == 200
  8. Set up the development environment

    master

    To contribute to responses, follow these steps to set up your local environment:

    1. Clone the repository:
      git clone https://github.com/getsentry/responses.git
    2. Create and activate a virtual environment:
      virtualenv .env && source .env/bin/activate
    3. Install development requirements:
      make develop
    git clone https://github.com/getsentry/responses.git
    virtualenv .env && source .env/bin/activate
    make develop
  9. Setup development environment

    master

    To contribute to responses, clone the repository, create a virtual environment, and run the make develop command to configure development requirements.

    git clone https://github.com/getsentry/responses.git
    
    virtualenv .env && source .env/bin/activate
    
    make develop
  10. Use responses with coroutines and multithreading

    master

    The responses library supports both coroutines (async/await) and multithreading natively. Note that responses locks the thread on the RequestMock object, ensuring that only one thread accesses it at a time.

    async def test_async_calls():
        @responses.activate
        async def run():
            responses.get(
                "http://twitter.com/api/1/foobar",
                json={"error": "not found"},
                status=404,
            )
    
            resp = requests.get("http://twitter.com/api/1/foobar")
            assert resp.json() == {"error": "not found"}
            assert responses.calls[0].request.url == "http://twitter.com/api/1/foobar"
    
        await run()
  11. Run tests and quality validation

    master

    Use tox to run the full suite of validations, including unit tests across supported Python versions, mypy type checking, and pre-commit hooks.

    Run all validations:

    tox

    Run specific Python version tests:

    tox -e py38
    tox -e py310

    Run unit tests with pytest: If you have the environment activated, you can use pytest directly:

    • All tests: pytest
    • Specific test: pytest -k '<test_function_name>'
    tox
    tox -e py38
    tox -e py310
    pytest
    pytest -k '<test_function_name>'