python – How can I mock requests and the response?

python – How can I mock requests and the response?

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!

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.

Theres also HTTPretty:

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

Theres also httmock.

python – How can I mock requests and the response?

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)))

Leave a Reply

Your email address will not be published. Required fields are marked *