Skip to content

Warning

This is the documentation of the older version `0.14.0`. See latest for current release.

# Developer Interface - Version 0.14.0

## Mocking Responses

### HTTP Method API

For regular and simple use, use the HTTP method shorthands. See Request API for parameters.

> `respx.get`(url=None, *, name=None, **lookups)

> `respx.options(...)`

> `respx.head(...)`

> `respx.post(...)`

> `respx.put(...)`

> `respx.patch(...)`

> `respx.delete(...)`

### Request API

For full control, use the core `add` method.

> `respx.add`(route, *, name=None)

> Parameters:

> - method - str | callable | RequestPattern
>   Request HTTP method, or Request callback, to match.
> - url - (optional) str | pattern | tuple (httpcore) | httpx.URL
>   Request exact URL, or URL pattern, to match.
> - params - (optional) str | list | dict
>   Request URL params to merge with url.
> - status_code - (optional) int - default: `200`
>   Response status code to mock.
> - headers - (optional) dict
>   Response headers to mock.
> - content_type - (optional) str
>   Response Content-Type header value to mock.
> - content - (optional) bytes | str | list | dict | callable | exception - default `b""`
>   Response content to mock. - See Response Content.
> - text - (optional) str
>   Response text content to mock, with automatic content type header.
> - html - (optional) str
>   Response html content to mock, with automatic content type header.
> - json - (optional) str | list | dict
>   Response json content to mock, with automatic content type header.
> - pass_through - (optional) bool - default `False`
>   Mark matched request to pass-through to real server, e.g. don't mock.
> - alias - (optional) str
>   Name this request pattern. - See Call Statistics.

## Matching Requests

### Exact URL

To match and mock a request by an exact URL, pass the `url` parameter as a string.

    respx.get("https://foo.bar/", status_code=204)

### URL pattern

Instead of matching an exact URL, you can pass a compiled regex to match the request URL.

    import httpx
    import re
    import respx

    @respx.mock
    def test_something():
        url_pattern = re.compile(r"^https://foo.bar/\w+/$")
        respx.get(url_pattern, content="Baz")
        response = httpx.get("https://foo.bar/baz/")
        assert response.text == "Baz"

Tip

Named groups in the regex pattern will be passed as `kwargs` to the response content callback, if used.

### Base URL

When adding a lot of request patterns sharing the same domain/prefix, you can configure RESPX with a `base_url` to use as the base when matching URLs.

Like `url`, the `base_url` can also be passed as a compiled regex, with optional named groups.

    import httpx
    import respx

    @respx.mock(base_url="https://foo.bar")
    async def test_something(respx_mock):
        async with httpx.AsyncClient(base_url="https://foo.bar") as client:
            request = respx_mock.get("/baz/", content="Baz")
            response = await client.get("/baz/")
            assert response.text == "Baz"

### Request callback

For full control of what request to match and what response to mock, pass a callback function as the `add(method, ...)` parameter. The callback's response argument will be pre-populated with any additional response parameters.

    import httpx
    import respx

    def match_and_mock(request, response):
        """
        Return `None` to not match the request.
        Return the `response` to match and mock this request.
        Return the `request` for pass-through behaviour.
        """
        if request.method != "POST":
            return None

        if "X-Auth-Token" not in request.headers:
            response.status_code = 401
        else:
            response.content = "OK"

        return response

    @respx.mock
    def test_something():
        custom_request = respx.add(match_and_mock, status_code=201)
        respx.get("https://foo.bar/baz/")

        response = httpx.get("https://foo.bar/baz/")
        assert response.status_code == 200
        assert not custom_request.called

        response = httpx.post("https://foo.bar/baz/")
        assert response.status_code == 401
        assert custom_request.called

        response = httpx.post("https://foo.bar/baz/", headers={"X-Auth-Token": "x"})
        assert response.status_code == 201
        assert custom_request.call_count == 2

### Repeated patterns

If you mock several responses with the same request pattern, they will be matched in order, and popped til the last one.

    import httpx
    import respx

    @respx.mock
    def test_something():
        respx.get("https://foo.bar/baz/123/", status_code=404)
        respx.get("https://foo.bar/baz/123/", content={"id": 123})
        respx.post("https://foo.bar/baz/", status_code=201)

        response = httpx.get("https://foo.bar/baz/123/")
        assert response.status_code == 404  # First match

        response = httpx.post("https://foo.bar/baz/")
        assert response.status_code == 201

        response = httpx.get("https://foo.bar/baz/123/")
        assert response.status_code == 200  # Second match
        assert response.json() == {"id": 123}

### Manipulating Existing Patterns

Clearing all existing patterns:

    import respx

    @respx.mock
    def test_something():
        respx.get("https://foo.bar/baz", status_code=404)
        respx.clear()  # no patterns will be matched after this call

Removing and optionally re-using an existing pattern by alias:

    import respx

    @respx.mock
    def test_something():
        respx.get("https://foo.bar/", status_code=404, alias="index")
        request_pattern = respx.pop("index")
        respx.get(request_pattern.url, status_code=200)

## Response Content

### JSON content

To mock a response with json content, pass a `list` or a `dict`.
The `Content-Type` header will automatically be set to `application/json`.

    import httpx
    import respx

    @respx.mock
    def test_something():
        respx.get("https://foo.bar/baz/123/", content={"id": 123})
        response = httpx.get("https://foo.bar/baz/123/")
        assert response.json() == {"id": 123}

### Content callback

If you need dynamic response content, pass a callback function.
When used together with a URL pattern, named groups will be passed as `kwargs`.

    import httpx
    import re
    import respx

    def some_content(request, slug=None):
        """ Return bytes, str, list or a dict. """
        return {"slug": slug}

    @respx.mock
    def test_something():
        url_pattern = r"^https://foo.bar/(?P<slug>\w+)/$")
        respx.get(url_pattern, content=some_content)

        response = httpx.get("https://foo.bar/apa/")
        assert response.json() == {"slug": "apa"}

### Request Error

To simulate a failing request, like a connection error, pass an `Exception` instance. This is useful when you need to test proper `HTTPX` error handling in your app.

    import httpx
    import httpcore
    import respx

    @respx.mock
    def test_something():
        respx.get("https://foo.bar/", content=httpcore.ConnectTimeout())
        response = httpx.get("https://foo.bar/")  # Will raise

## Built-in Assertions

RESPX has the following built-in assertion checks:

> - assert_all_mocked
>   Asserts that all captured `HTTPX` requests are mocked. Defaults to `True`.
> - assert_all_called
>   Asserts that all mocked request patterns were called. Defaults to `True`.

Configure checks by using the `respx.mock` decorator / context manager with parentheses.

    @respx.mock(assert_all_called=False)
    def test_something(respx_mock):
        respx_mock.get("https://some.url/")  # OK
        respx_mock.get("https://foo.bar/")

        response = httpx.get("https://foo.bar/")
        assert response.status_code == 200
        assert respx_mock.calls.call_count == 1

    with respx.mock(assert_all_mocked=False) as respx_mock:
        response = httpx.get("https://foo.bar/")  # OK
        assert response.status_code == 200
        assert respx_mock.calls.call_count == 1

Without Parentheses

When using the global scope `@respx.mock` decorator / context manager, `assert_all_called` is disabled.

## Call History

The `respx` API includes a `.calls` object, containing captured (`request`, `response`) named tuples and MagicMock's bells and whistles, i.e. `call_count`, `assert_called` etc.

### Retrieving mocked calls

A matched and mocked `Call` can be retrieved from call history, by either unpacking...

    request, response = respx.calls.last
    request, response = respx.calls[-2]  # by call order

...or by accessing `request` or `response` directly...

    last_response = respx.calls.last.response

    assert respx.calls.last.request.call_count == 1
    assert respx.calls.last.response.status_code == 200

Deprecation Warning

As of version `0.14.0`, statistics via `respx.stats` is deprecated, in favour of `respx.calls`.

### Request Pattern calls

Each mocked response request pattern has its own `.calls`, along with `.called` and `.call_count` stats shortcuts.

Example using locally added request pattern:

    import httpx
    import respx

    @respx.mock
    def test_something():
        request = respx.post("https://foo.bar/baz/", status_code=201)
        httpx.post("https://foo.bar/baz/")
        assert request.called
        assert request.call_count == 1
        assert request.calls.last.response.status_code == 201
        request.calls.assert_called_once()

Example using globally aliased request pattern:

    import httpx
    import respx

    # Added somewhere outside the test
    respx.get("https://foo.bar/", alias="index")

    @respx.mock
    def test_something():
        httpx.get("https://foo.bar/")
        assert respx.aliases["index"].called
        assert respx.aliases["index"].call_count == 1
        last_index_response = respx.aliases["index"].calls.last.response

### Reset stats

To reset stats during a test case, without stop mocking, use `respx.reset()`.

    import httpx
    import respx

    @respx.mock
    def test_something():
        respx.post("https://foo.bar/baz/")
        httpx.post("https://foo.bar/baz/")
        assert respx.calls.call_count == 1
        request.calls.assert_called_once()

        respx.reset()
        assert len(respx.calls) == 0
        assert respx.calls.call_count == 0
        respx.calls.assert_not_called()

### Examples

Here's a handful example usages of the call stats API.

    import httpx
    import respx

    @respx.mock
    def test_something():
        # Mock some calls
        respx.get("https://foo.bar/", alias="index")
        baz_request = respx.post("https://foo.bar/baz/", status_code=201)

        # Make some calls
        httpx.get("https://foo.bar/")
        httpx.post("https://foo.bar/baz/")

        # Assert mocked
        assert respx.aliases["index"].called
        assert respx.aliases["index"].call_count == 1

        assert baz_request.called
        assert baz_request.call_count == 1
        baz_request.calls.assert_called_once()

        # Global stats increased
        assert respx.calls.call_count == 2

        # Assert responses
        assert respx.aliases["index"].calls.last.response.status_code == 200
        assert respx.calls.last.response is baz_request.calls.last.response
        assert respx.calls.last.response.status_code == 201

        # Reset
        respx.reset()
        assert len(respx.calls) == 0
        assert respx.calls.call_count == 0
        respx.calls.assert_not_called()