Python mock requests.post to throw exception

17,322

Mock the requests.post function, and on the mock set the side_effect attribute to the desired exception:

@patch('requests.post')
def test_request_post_exception(self, post_mock):
    post_mock.side_effect = requests.exceptions.ConnectionError()
    # run your test, code calling `requests.post()` will trigger the exception.

From the linked documentation:

This can either be a function to be called when the mock is called, an iterable or an exception (class or instance) to be raised.

[...]

An example of a mock that raises an exception (to test exception handling of an API):

>>> mock = Mock()
>>> mock.side_effect = Exception('Boom!')
>>> mock()
Traceback (most recent call last):
  ...
Exception: Boom!

(Bold emphasis mine).

This is also covered in the Quick Guide section:

side_effect allows you to perform side effects, including raising an exception when a mock is called:

>>> mock = Mock(side_effect=KeyError('foo'))
>>> mock()
Traceback (most recent call last):
 ...
KeyError: 'foo'
Share:
17,322

Related videos on Youtube

camelBack
Author by

camelBack

Updated on September 16, 2022

Comments

  • camelBack
    camelBack over 1 year

    Using Python 3.5, requests==2.18.4, Flask==0.12.2, urllib3==1.22

    I have a method some_method in my main server.py file, that is supposed to make a POST to some url with some data:

    def some_method(url, data):
        ...
        error = None
        try:
            response = requests.post(url, json=data)
        except requests.exceptions.ConnectionError as e:
            ...
            app.logger.error(...)
            response = None
            error = str(e)
        return error, response
    

    The server file defines: app = Flask(__name__), and some_method is called from @app.route(... methods=['PATCH']).
    If this method throws an error, the route will eventually return a 500.

    Tests are run from a test file importing the app with import server and app = server.app, using unittest, and importing mock.patch.

    I am able to test the overall app behavior, with a test that shows that the app route behave as expected when the method returns an error and seeing that the route terminates at the right spot:

    class ServerTestCase(unittest.TestCase):
        ...
        @patch('server.some_method')
        def test_route_response_status_500_when_throws(self, mock_response):
            mock_response.return_value = 'some_error_string', None
            response = self.app.patch(some_url, some_data, content_type='application/json')
            self.assertEqual(response.status_code, 500)
    

    However, I would really like to have another test to test some_method in isolation:

    1. Mock requests.post to throw requests.exceptions.ConnectionError
    2. Show that the method logs an error (I know I can mock my app.logger and assert that it logged during the execution)
    • Martijn Pieters
      Martijn Pieters
      So where did you get stuck? You can mock requests.post just fine, and you can have a mock raise exceptions by setting the side_effects attribute.
  • camelBack
    camelBack about 6 years
    Thank you! I was doing what you mentioned in your response, but I had a few errors: 1. requests.exceptions.ConnectionError -> requests.exceptions.ConnectionError() 2. Was trying many variations of patch, also object but then changed to -> @patch('requests.post')