python mock Requests and the response
Question: I am a beginner to using mock in python and trying to use
<http://www.voidspace.org.uk/python/mock>. Please tell me the basic calls to
get me working in below scenario. I am using pythons Requests module.

In my views.py, I have a function that makes variety of requests.get() calls
with different response each time

    
    
    def myview(request):
      res1 = requests.get('aurl')
      res2 = request.get('burl')
      res3 = request.get('curl')
    

In my test class I want to do something like this but cannot figure out exact
method calls

Step 1:

    
    
    //Mock the requests module
    //when mockedRequests.get('aurl') is called then return 'a response'
    //when mockedRequests.get('burl') is called then return 'b response'
    //when mockedRequests.get('curl') is called then return 'c response'
    

Step 2:

Call my view

Step 3:

verify response contains 'a response', 'b response' , 'c response'

Please help me to complete Step 1.


Answer: 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)
        else:
            return MockResponse({"key2": "value2"}, 200)
    
        return MockResponse({}, 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"})
    
            # 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), 2)
    
    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!

