pythonpytestrequests-mock

How to simulate request timeout and then succeed with requests_mock


I use requests_mock with pytest. I would like to configure a requests_mock object to raise an exception (requests.exceptions.ReadTimeout) a few times and then succeed. How can I do that?

I know how to return various HTTP requests (pass a list to response_list) and how to always raise an exception (using the exc argument) but I don't know how to combine this.

To give some context, I want to test a function that retry on some errors, including requests.exceptions.ReadTimeout, thanks to Tenacity. The goal is to test that the function re-run on a few exceptions and then succeed.

Basically, this is similar to this question but in Python.


Solution

  • To simulate a few timeouts and then a successful response using requests_mock in your pytest test do this:

    import requests
    import requests_mock
    import pytest
    
    def test_retry_then_success():
        # Create a mock that raises ReadTimeout twice, then returns success
        responses = [
            {'exc': requests.exceptions.ReadTimeout},  # 1st call -> timeout
            {'exc': requests.exceptions.ReadTimeout},  # 2nd call -> timeout
            {'text': 'OK', 'status_code': 200},        # 3rd call -> success
        ]
    
        with requests_mock.Mocker() as m:
            m.get('https://example.com', response_list=responses)
    
            call_count = 0
            for _ in range(3):
                try:
                    r = requests.get('https://example.com', timeout=1)
                    call_count += 1
                    if r.status_code == 200:
                        assert r.text == 'OK'
                        break
                except requests.exceptions.ReadTimeout:
                    call_count += 1
    
            assert call_count == 3
    

    Explanation :

    If you’re testing a retry-enabled function (say my_function()), just replace the loop with a single call:

    with requests_mock.Mocker() as m:
        m.get('https://example.com', response_list=responses)
        result = my_function()
        assert result == 'OK'
    

    This pattern is the canonical way to simulate intermittent failures and recovery with requests_mock.