In Python, the requests
library is widely used for sending HTTP requests and handling responses. It provides a simple and intuitive interface for making HTTP calls and is often used in web scraping, API consumption, and testing.
This blog post will focus on testing and mocking requests in Python, specifically using the requests-mock
library. requests-mock
allows you to effectively test code that interacts with external APIs by simulating HTTP requests and responses.
Installation
To get started, you need to install the requests
and requests-mock
libraries in your Python environment. You can use the following pip
command to install both libraries:
pip install requests requests-mock
Basic Usage
Here’s a basic example of how to use requests-mock
to mock requests in your tests:
import requests
import requests_mock
with requests_mock.Mocker() as mocker:
mocker.register_uri(
'GET',
'https://api.example.com/users',
json={'users': [{'name': 'John'}, {'name': 'Jane'}]}
)
response = requests.get('https://api.example.com/users')
data = response.json()
assert response.status_code == 200
assert data['users'][0]['name'] == 'John'
In the above example, we use requests-mock
to mock a GET
request to the specified URL (https://api.example.com/users
). We define the response body as a JSON object with a list of users. We then make a request using requests
as usual and verify that the response status code is 200 and the first user’s name is “John”.
Advanced Usage
requests-mock
provides more advanced features to mock different types of requests and responses, handle multiple endpoints, and dynamically generate responses. Here are a few examples:
Mocking Different Types of Requests
import requests
import requests_mock
with requests_mock.Mocker() as mocker:
mocker.get('https://api.example.com/get', json={'response': 'GET'})
mocker.post('https://api.example.com/post', json={'response': 'POST'})
mocker.put('https://api.example.com/put', json={'response': 'PUT'})
mocker.delete('https://api.example.com/delete', json={'response': 'DELETE'})
get_response = requests.get('https://api.example.com/get')
post_response = requests.post('https://api.example.com/post')
put_response = requests.put('https://api.example.com/put')
delete_response = requests.delete('https://api.example.com/delete')
assert get_response.json()['response'] == 'GET'
assert post_response.json()['response'] == 'POST'
assert put_response.json()['response'] == 'PUT'
assert delete_response.json()['response'] == 'DELETE'
In this example, we mock different types of requests (GET
, POST
, PUT
, DELETE
) to different endpoints and verify that the responses match the expected values.
Handling Multiple Endpoints
import requests
import requests_mock
with requests_mock.Mocker() as mocker:
mocker.get('https://api.example.com/users', json={'users': [{'name': 'John'}]})
mocker.get('https://api.example.com/products', json={'products': [{'name': 'Keyboard'}]})
users_response = requests.get('https://api.example.com/users')
products_response = requests.get('https://api.example.com/products')
assert users_response.json()['users'][0]['name'] == 'John'
assert products_response.json()['products'][0]['name'] == 'Keyboard'
In this example, we mock requests to different endpoints (/users
and /products
) and verify that the responses contain the expected data.
Dynamic Responses
import requests
import requests_mock
def dynamic_response(request, context):
if 'users' in request.url:
context.status_code = 200
context.json = {'users': [{'name': 'John'}]}
elif 'products' in request.url:
context.status_code = 200
context.json = {'products': [{'name': 'Keyboard'}]}
else:
context.status_code = 404
with requests_mock.Mocker() as mocker:
mocker.get('https://api.example.com', json=dynamic_response)
users_response = requests.get('https://api.example.com/users')
products_response = requests.get('https://api.example.com/products')
unknown_response = requests.get('https://api.example.com/unknown')
assert users_response.json()['users'][0]['name'] == 'John'
assert products_response.json()['products'][0]['name'] == 'Keyboard'
assert unknown_response.status_code == 404
In this example, we define a dynamic response function (dynamic_response
) that examines the request URL and generates appropriate responses based on the URL path. We then register this function as the response for any request to https://api.example.com
. We verify that the responses contain the expected data or return a 404
status code if the URL is unknown.
Conclusion
Testing and mocking requests in Python is crucial when developing applications that rely on external APIs. The requests-mock
library simplifies the process of mocking requests and responses, allowing you to effectively test your code. With the techniques discussed in this blog post, you can confidently test your code’s behavior in a controlled environment without the need for real network requests. Happy testing!