jamielennox / requests-mock

Mocked responses for the requests library
https://requests-mock.readthedocs.io
Apache License 2.0
450 stars 71 forks source link

Add support for exception callback #241

Open timobrembeck opened 1 year ago

timobrembeck commented 1 year ago

I'm working on django-linkcheck, a library that periodically checks the status of URLs.

Apart from the validity of the SSL certificate, we are also interested in the result of a URL when ignoring certificate verification. To do so, we perform an initial request, and if this fails with an SSLError, we perform a subsequent request with setting verify to False. In order for us to test this, we would need the possibility to register an uri that raises a SSLError when called with verify=True and a valid response then requesting with verify=False. The corresponding information is already contained in the request object that is passed to the callback functions, however this does not work for exceptions.

So my suggestion would be something along the lines of:

  1. Either provide the option to calculate all combined kwargs in one callable
  2. Or provide the option to pass the exception as a callable and remove this check to be able to pass "fallback" arguments in case the exception callback returns None instead of an exception.

I would be happy to implement this, in case you think the reasoning behind this change is valid and also provides value for other users as well.

jamielennox commented 10 months ago

Hi, sorry for the delay in responding. Isn't this something that just works out of the box? If you throw an exception in the callback function it will bubble up to the requests function that you can handle like normal?

import requests
import requests_mock

with requests_mock.Mocker() as m:
    url = 'https://httpbin.org/get'

    def cb(req, ctx):
        if req.verify:
            raise requests.exceptions.SSLError()

        return "hello"

    m.get(
        url=url,
        status_code=200,
        text=cb,
    )

    try:
        requests.get(url)
    except requests.exceptions.SSLError as e:
        print("SSL error thrown")
    else:
        assert False, "failed to throw error"

    assert requests.get(url, verify=False).text == "hello"
    print("Passes when verify false")
jamielennox commented 10 months ago

Another way you could do it if you wanted to check the actual order that your app created the requests is to register a list of responses, on the first one register the exc= on the second one the body, and then you'd inspect the history to ensure that your app issued the verify= in the correct order. It's clunkier, but i kind of feel that you should be testing your app and not putting too much into the mock logic so checking the history is always a good idea.