Hi,
I'm currently using https://github.com/getsentry/responses for testing an app that's using requests. Is there anything similar for httpx?
Thanks for the library!
Hi @svanburen! responses looks like a neat utility. I don't think an equivalent for HTTPX exists yet, though. But let's see if it could be built, and how!
From what I can see in the code, the way responses works is it monkeypatches requests.adapters.HTTPAdapter.send with a version that pops a matching response from those added via responses.add(), and pushes it to the call stack. This effectively results in the request not being actually dispatched to the network.
I suppose an equivalent of responses for HTTPX would be able to use the same idea, but with the target of the monkeypatch being ConnectionPool.send(), e.g…
import unittest.mock
import httpx
_real_send = httpx.ConnectionPool.send
# ...
class HTTPXMock:
# ...
def start(self):
async def new_send(request, *args, **kwargs):
return await self._on_request(request, *args, **kwargs)
self._patcher = unittest.mock.patch(target="httpx.ConnectionPool.send", new=new_send)
self._patcher.start()
async def _on_request(self, request, *args, **kwargs):
# TODO: an actual implementation :-)
return await _real_send(request, *args, **kwargs)
# ...
I suspect the implementation would be very similar to that of responses, just adapted to match the internals of HTTPX.
On the user side, the API of the resulting library (httpx-responses?) would probably be 100% compatible with that of responses.
For example, here's a copy-pasted version of the quickstart example from the responses README with aliases from httpx and httpx-responses:
import httpx_responses as responses
import httpx as requests
@responses.activate
def test_simple():
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 len(responses.calls) == 1
assert responses.calls[0].request.url == 'http://twitter.com/api/1/foobar'
assert responses.calls[0].response.text == '{"error": "not found"}'
A useful pattern here may be to plug the client into a simple WSGI or ASGI app when you want to mock out a set of responses.
For instance if you’re testing a web app that makes some outgoing requests, you could make sure to instantiate a standard client when you’re running the live app, but swap the client out for one that points at a mocked out service when running the test suite.
Good point @tomchristie — this reminds me of a recent article that covers exactly that, i.e. mocking an external service with Starlette and HTTPX for testing purposes: Quick and dirty mock service with Starlette.
So, I think the original question for this issue has been answered, I'm going to close this for now. :-) Thanks!
just wanted to pop in to say thanks again for all the helpful details here, appreciate the discussion and the project in general!
As the related and merged PR #537 addresses, RESPX is documented as an responses equivalent for HTTPX.
Most helpful comment
As the related and merged PR #537 addresses, RESPX is documented as an
responsesequivalent forHTTPX.