Skip to content

Instantly share code, notes, and snippets.

@evansde77
Last active November 1, 2024 13:38
Show Gist options
  • Save evansde77/45467f5a7af84d2a2d34f3fcb357449c to your computer and use it in GitHub Desktop.
Save evansde77/45467f5a7af84d2a2d34f3fcb357449c to your computer and use it in GitHub Desktop.
Example of mocking requests calls
#!/usr/bin/env python
"""
mocking requests calls
"""
import mock
import unittest
import requests
from requests.exceptions import HTTPError
def google_query(query):
"""
trivial function that does a GET request
against google, checks the status of the
result and returns the raw content
"""
url = "https://www.google.com"
params = {'q': query}
resp = requests.get(url, params=params)
resp.raise_for_status()
return resp.content
class TestRequestsCall(unittest.TestCase):
"""
example text that mocks requests.get and
returns a mock Response object
"""
def _mock_response(
self,
status=200,
content="CONTENT",
json_data=None,
raise_for_status=None):
"""
since we typically test a bunch of different
requests calls for a service, we are going to do
a lot of mock responses, so its usually a good idea
to have a helper function that builds these things
"""
mock_resp = mock.Mock()
# mock raise_for_status call w/optional error
mock_resp.raise_for_status = mock.Mock()
if raise_for_status:
mock_resp.raise_for_status.side_effect = raise_for_status
# set status code and content
mock_resp.status_code = status
mock_resp.content = content
# add json data if provided
if json_data:
mock_resp.json = mock.Mock(
return_value=json_data
)
return mock_resp
@mock.patch('requests.get')
def test_google_query(self, mock_get):
"""test google query method"""
mock_resp = self._mock_response(content="ELEPHANTS")
mock_get.return_value = mock_resp
result = google_query('elephants')
self.assertEqual(result, 'ELEPHANTS')
self.assertTrue(mock_resp.raise_for_status.called)
@mock.patch('requests.get')
def test_failed_query(self, mock_get):
"""test case where google is down"""
mock_resp = self._mock_response(status=500, raise_for_status=HTTPError("google is down"))
mock_get.return_value = mock_resp
self.assertRaises(HTTPError, google_query, 'elephants')
if __name__ == '__main__':
unittest.main()
@imrek
Copy link

imrek commented May 1, 2017

Thank you for this example.

@curious-codr
Copy link

curious-codr commented Sep 12, 2017

How to mock request object with json keyvalue pairs

@lcantonelli
Copy link

Great

@malhotra18
Copy link

Awsome example.. Thanks :)

@4lberto
Copy link

4lberto commented Apr 25, 2018

Thank you!!! very clear and simple

@zerogvt
Copy link

zerogvt commented Jul 23, 2018

👍

@Michael98Liu
Copy link

Hi, thanks for the gist. I have a question about the test_fail_query function. Why it doesn't work if I change self.assertRaises(HTTPError, google_query, 'elephants') to self.assertRaises(HTTPError, mock_get)? Since the status code is 500. Shouldn't HTTPError be raised?

@evansde77
Copy link
Author

Hi, thanks for the gist. I have a question about the test_fail_query function. Why it doesn't work if I change self.assertRaises(HTTPError, google_query, 'elephants') to self.assertRaises(HTTPError, mock_get)? Since the status code is 500. Shouldn't HTTPError be raised?

mock_get is just the call to request get that returns a response object, that response's raise_for_status method is what triggers the HTTPError, so the equivalent behaviour would be something like this:

    @mock.patch('requests.get')
    def test_failed_query(self, mock_get):
        """test case where google is down"""
        mock_resp = self._mock_response(status=500, raise_for_status=HTTPError("google is down"))
        mock_get.return_value = mock_resp
        resp = mock_get()
        self.assertRaises(HTTPError, resp.raise_for_status, 'elephants')

Hope that helps!

@saimkhan92
Copy link

saimkhan92 commented Oct 4, 2018

Great example. I wanted to know what difference would it make if we get rid of line 46 in the helper function. Will the following code not produce the same end result?


def _mock_response(
            self,
            status=200,
            content="CONTENT",
            json_data=None,
            raise_for_status=None):
        """
        since we typically test a bunch of different
        requests calls for a service, we are going to do
        a lot of mock responses, so its usually a good idea
        to have a helper function that builds these things
        """
        mock_resp = mock.Mock()
        # mock raise_for_status call w/optional error
        if raise_for_status:
            mock_resp.raise_for_status.side_effect = raise_for_status
        # set status code and content
        mock_resp.status_code = status
        mock_resp.content = content
        # add json data if provided
        if json_data:
            mock_resp.json = mock.Mock(
                return_value=json_data
            )
        return mock_resp

Thanks.

@sthota18
Copy link

Thank you so much for this example.

@MaxIakovliev
Copy link

Thank you

@NicoLiendro14
Copy link

Thank you so much for this example.

@fazith27
Copy link

fazith27 commented May 3, 2021

Thank you

@eocampo421
Copy link

Thank you!!

@sbadiyani-eightfold
Copy link

Thank you!

@alliswave
Copy link

it helped me a LOT, thanks so much.

@ductrung-nguyen
Copy link

Thank you

@sagaraivale
Copy link

Hey @evansde77 : Really nice snippet to get the knowledge of mocking requests API calls with raise_for_status scenario.

I would just recommend one thing here, instead of mocking actual request.get library, we should add patch at mock_requests.request.get. In this way, we are truly mocking actual object.

Let me know your thoughts on this!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment