Httpx: responses-like alternative for httpx

Created on 1 Nov 2019  Â·  7Comments  Â·  Source: encode/httpx

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!

question requests-compat

Most helpful comment

As the related and merged PR #537 addresses, RESPX is documented as an responses equivalent for HTTPX.

All 7 comments

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.

I have also wanted to add support for httpx to vcrpy (docs), as auto-recording responses would be a fantastic feature for mocks as well.

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.

Was this page helpful?
0 / 5 - 0 ratings