How can I mock requests and the response?
This is how you can do it (you can run this file as-is):
import requestsimport unittestfrom unittest import mock# This is the class we want to testclass MyGreatClass: def fetch_json(self, url): response = requests.get(url) return response.json()# This method will be used by the mock to replace requests.getdef 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 classclass 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 unittestfrom unittest import mockfrom my.great.package import MyGreatClass# This method will be used by the mock to replace requests.getdef mocked_requests_get(*args, **kwargs): # Same as aboveclass 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 aboveif __name__ == '__main__': unittest.main()
Enjoy!
Try using the responses library. Here is an example from their documentation:
import responsesimport requests@responses.activatedef 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.