Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add httpx.MockTransport() #1401

Merged
merged 7 commits into from Jan 6, 2021
Merged

Add httpx.MockTransport() #1401

merged 7 commits into from Jan 6, 2021

Conversation

tomchristie
Copy link
Member

@tomchristie tomchristie commented Nov 25, 2020

Closes #1303

Docs as follows...


Mock transports

During testing it can often be useful to be able to mock out a transport, and return pre-determined responses, rather than making actual network requests.

The httpx.MockTransport class accepts a handler function, which can be used to map requests onto pre-determined responses:

def handler(request):
    return httpx.Response(200, json={"text": "Hello, world!"})


# Switch to a mock transport, if the TESTING environment variable is set.
if os.environ['TESTING'].upper() == "TRUE":
    transport = httpx.MockTransport(handler)
else:
    transport = httpx.HTTPTransport()

client = httpx.Client(transport=transport)

For more advanced use-cases you might want to take a look at the third-party mocking library, RESPX, or the pytest-httpx library.

@tomchristie tomchristie added the enhancement New feature or request label Nov 25, 2020
Copy link
Member

@florimondmanca florimondmanca left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Superb! Excitingly clean. :-)

@lundberg
Copy link
Contributor

Hooray 🎉

Latest release of RESPX (0.16.2) now has optional support for not patching the httpcore transports, and passing a RESPX router handler to the MockTransport.

import httpx
import respx


mock_router = respx.MockRouter(using=None)
route = mock_router.get("https://example.org/").mock(return_value=httpx.Response(204))

transport = httpx.MockTransport(mock_router.handler)

with httpx.Client(transport=transport) as client:
    response = client.get("https://example.org/")
    assert response.status_code == 204
    assert route.called

Copy link
Member

@florimondmanca florimondmanca left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💯

@tomchristie tomchristie mentioned this pull request Nov 30, 2020
3 tasks
@florimondmanca florimondmanca added this to the v0.17 milestone Nov 30, 2020
@tomchristie tomchristie merged commit 9c7c2ac into master Jan 6, 2021
@tomchristie tomchristie deleted the mock-transport branch January 6, 2021 11:04
@simonw
Copy link
Contributor

simonw commented Jan 8, 2021

Last minute suggestion: it looks like the handler function currently cannot be an async def ... function, even for the async version of the mock transport:

request = Request(
method=method,
url=url,
headers=headers,
stream=stream,
)
await request.aread()
response = self.handler(request)
return (
response.status_code,
response.headers.raw,
response.stream,
response.ext,
)

I can imagine cases where I might want to be able to write a handler function that uses await ... - to access an async database layer for example.

Maybe apply something like the await me maybe pattern here, so users can define a regular function or an async function for their handler?

@florimondmanca
Copy link
Member

@simonw Yes, that sounds pretty sensible, thanks for noticing! :) I also think async mock views could be useful to me in some cases. I'm not sure we need to impose "async def for async client", so something like await me maybe sounds sensible...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add httpx.MockTransport()
4 participants