Contents

Simplify HTTP Request Mocking in Python with Responses

One of the most tedious tasks in testing code that interacts with external APIs is mocking HTTP requests. It can be time-consuming to set up mocks for each request, and it can be difficult to verify that the request body matches your expected payload.

Thankfully, there’s a Python library called Responses that can simplify this process for you. In this article, we’ll explore how responses can be used to mock HTTP requests in Python tests, and we’ll demonstrate how to compare request bodies with Python objects.

What is Responses?

Responses is a Python library that provides a simple and intuitive API for mocking HTTP requests. It allows you to define mock responses for specific URLs and HTTP methods, so that you can test your code in isolation without actually making real HTTP requests.

How to use Responses to mock HTTP requests

To use responses to mock HTTP requests, you’ll first need to install it using pip:

pip install responses

Once you’ve installed responses, you can use it in your Python tests. Here’s an example of how to mock a GET request:

import responses
import requests

@responses.activate
def test_my_code():
    responses.add(responses.GET, 'http://example.com/foo', status=200, json={'key': 'value'})

    response = requests.get('http://example.com/foo')

    assert response.status_code == 200
    assert response.json() == {'key': 'value'}

In this example, we’re using responses.add() to define a mock response for a GET request to http://example.com/foo. We’re specifying that the response should have a status code of 200 and a JSON body of {'key': 'value'}. Then, in our test function, we’re using the requests library to make a GET request to the same URL, and we’re asserting that the response we get back has the expected status code and JSON body.

Comparing request bodies with Python objects

Sometimes, you’ll want to compare request bodies with Python objects instead of with strict strings. To do this, you can use the json.loads() method to convert the request body to a Python object, and then compare that object to your expected object. Here’s an example:

import json
import responses
import requests

@responses.activate
def test_my_code():
    # Mock the PUT request
    responses.add(responses.PUT, 'http://example.com/foo', status=200)

    # Make the PUT request
    payload = {'key': 'value'}
    response = requests.put('http://example.com/foo', json=payload)

    # Check that the request was sent with the correct payload
    assert len(responses.calls) == 1
    assert responses.calls[0].request.url == 'http://example.com/foo'
    assert responses.calls[0].request.method == 'PUT'

    # Convert the request body to a Python object
    request_body = json.loads(responses.calls[0].request.body)

    # Compare the request body to our expected object
    assert request_body == payload

In this example, we’re still using json.loads() to convert the request body to a Python object, but instead of comparing it to a string, we’re comparing it to the payload dictionary that we passed to requests.put(). This will perform a deep comparison of the two objects and ensure that all keys and values match, regardless of their order or representation.

Conclusion

Mocking HTTP requests can be a tedious task, but using responses, it becomes much easier and faster. With the ability to define mock responses for specific URLs and HTTP methods, and the option to compare request bodies with Python objects, you can test your code in isolation and with more precision.

In addition to the examples shown here, responses provides many other features and options for mocking HTTP requests, such as response headers, timeouts, and exceptions. It’s a versatile library that can be used for a wide variety of testing scenarios.

If you’re a Python developer who needs to test code that interacts with external APIs, responses is definitely worth checking out. It can save you a lot of time and hassle, and make your tests more reliable and accurate.