Colin-b/pytest_httpx

How do simulate multiple responses, similar to `side_effect` in mock?

Closed this issue · 4 comments

I have a method where if a call received a 401 response, it then calls the auth API to refresh its auth token, and then re-issue the call with the new token. When done synchronously with requests, I can mock out the call with multiple responses in the side_effect parameter.

Moving to httpx and async calls, I'm stumped how to test this case. I tried adding multiple httpx_mock.add_reponse() calls, but of course that didn't work. Any advice?

Hello @EdLeafe ,

Can you confirm my understanding of the issue first?

  1. You want to mock a 401 response to URL1.
  2. You want to mock the auth API response with the token.
  3. You want to mock a 2xx response to URL1 with the provided token (in headers I assume)?

Ad placement: Please note that I am also the author of httpx-auth, aiming at handling authentication logic for you. ;)

Thanks for the ad, but we're using an internal auth system. 😁

The system caches auth tokens which expire after a period of time. So the general flow is this:

async def call_api(...):
    try:
       await make_request(<args with cached token>)
    except Unauthorized:
       new_token = get_new_token()
       await make_request(<args with new token>)

To test this case there are 3 async calls needed: failed auth, new token, succeed. How can I test the call_api() method with httpx?

You can match on headers, so I would do something along this line (assuming you send your token in the standard way):

def test_new_token_is_used_when_token_is_expired(httpx_mock):
    # Mock request with expired token response
    httpx_mock.add_response(match_headers={'Authorization': 'Bearer EXPIRED_TOKEN'}, status_code=401)
    # Mock new token response
    httpx_mock.add_response(url="AUTH_URL", json={"token": "NEW_TOKEN"})
    # Mock request with new token response
    httpx_mock.add_response(match_headers={'Authorization': 'Bearer NEW_TOKEN'})

Of course you have to return the proper body and filter on the proper information but that's the spirit. All those information can be found in the documentation.

Don't hesitate to ask if something is not clear. Always a good opportunity to clean up documentation.

ok, I think I understand. I guess that I wasn't using matching correctly. Thanks for the help!