python - How can I mock requests and the response?

ID : 10271

viewed : 38

Tags : pythonmockingrequestpython

Top 5 Answer for python - How can I mock requests and the response?

vote vote

93

This is how you can do it (you can run this file as-is):

import requests import unittest from unittest import mock  # This is the class we want to test class MyGreatClass:     def fetch_json(self, url):         response = requests.get(url)         return response.json()  # This method will be used by the mock to replace requests.get def mocked_requests_get(*args, **kwargs):     class MockResponse:         def __init__(self, json_data, status_code):             self.json_data = json_data             self.status_code = status_code          def json(self):             return self.json_data      if args[0] == 'http://someurl.com/test.json':         return MockResponse({"key1": "value1"}, 200)     elif args[0] == 'http://someotherurl.com/anothertest.json':         return MockResponse({"key2": "value2"}, 200)      return MockResponse(None, 404)  # Our test case class class MyGreatClassTestCase(unittest.TestCase):      # We patch 'requests.get' with our own method. The mock object is passed in to our test case method.     @mock.patch('requests.get', side_effect=mocked_requests_get)     def test_fetch(self, mock_get):         # Assert requests.get calls         mgc = MyGreatClass()         json_data = mgc.fetch_json('http://someurl.com/test.json')         self.assertEqual(json_data, {"key1": "value1"})         json_data = mgc.fetch_json('http://someotherurl.com/anothertest.json')         self.assertEqual(json_data, {"key2": "value2"})         json_data = mgc.fetch_json('http://nonexistenturl.com/cantfindme.json')         self.assertIsNone(json_data)          # We can even assert that our mocked method was called with the right parameters         self.assertIn(mock.call('http://someurl.com/test.json'), mock_get.call_args_list)         self.assertIn(mock.call('http://someotherurl.com/anothertest.json'), mock_get.call_args_list)          self.assertEqual(len(mock_get.call_args_list), 3)  if __name__ == '__main__':     unittest.main() 

Important Note: If your MyGreatClass class lives in a different package, say my.great.package, you have to mock my.great.package.requests.get instead of just 'request.get'. In that case your test case would look like this:

import unittest from unittest import mock from my.great.package import MyGreatClass  # This method will be used by the mock to replace requests.get def mocked_requests_get(*args, **kwargs):     # Same as above   class MyGreatClassTestCase(unittest.TestCase):      # Now we must patch 'my.great.package.requests.get'     @mock.patch('my.great.package.requests.get', side_effect=mocked_requests_get)     def test_fetch(self, mock_get):         # Same as above  if __name__ == '__main__':     unittest.main() 

Enjoy!

vote vote

89

Try using the responses library. Here is an example from their documentation:

import responses import requests  @responses.activate def test_simple():     responses.add(responses.GET, 'http://twitter.com/api/1/foobar',                   json={'error': 'not found'}, status=404)      resp = requests.get('http://twitter.com/api/1/foobar')      assert resp.json() == {"error": "not found"}      assert len(responses.calls) == 1     assert responses.calls[0].request.url == 'http://twitter.com/api/1/foobar'     assert responses.calls[0].response.text == '{"error": "not found"}' 

It provides quite a nice convenience over setting up all the mocking yourself.

There's also HTTPretty:

It's not specific to requests library, more powerful in some ways though I found it doesn't lend itself so well to inspecting the requests that it intercepted, which responses does quite easily

There's also httmock.

vote vote

75

Here is what worked for me:

import mock @mock.patch('requests.get', mock.Mock(side_effect = lambda k:{'aurl': 'a response', 'burl' : 'b response'}.get(k, 'unhandled request %s'%k))) 
vote vote

67

I used requests-mock for writing tests for separate module:

# module.py import requests  class A():      def get_response(self, url):         response = requests.get(url)         return response.text 

And the tests:

# tests.py import requests_mock import unittest  from module import A   class TestAPI(unittest.TestCase):      @requests_mock.mock()     def test_get_response(self, m):         a = A()         m.get('http://aurl.com', text='a response')         self.assertEqual(a.get_response('http://aurl.com'), 'a response')         m.get('http://burl.com', text='b response')         self.assertEqual(a.get_response('http://burl.com'), 'b response')         m.get('http://curl.com', text='c response')         self.assertEqual(a.get_response('http://curl.com'), 'c response')  if __name__ == '__main__':     unittest.main() 
vote vote

56

this is how you mock requests.post, change it to your http method

@patch.object(requests, 'post') def your_test_method(self, mockpost):     mockresponse = Mock()     mockpost.return_value = mockresponse     mockresponse.text = 'mock return'      #call your target method now 

Top 3 video Explaining python - How can I mock requests and the response?

Related QUESTION?