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 capturedHTTPXrequests are mocked. Defaults toTrue.- assert_all_called
Asserts that all mocked request patterns were called. Defaults toTrue.
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()