Summary: In this tutorial, you’ll learn how to mock the requests
module in Python to test an API call using the unittest module.
The requests
module is an HTTP library that allows you to send HTTP requests easily. Typically, you use the requests
module to call an API from a remote server.
The scenario
For the demo purposes, we’ll use a public API provided by jsonplaceholder.typicode.com:
https://jsonplaceholder.typicode.com/
Code language: Python (python)
To make an API call, you’ll use the requests
method to send an HTTP GET method to the following end-point:
https://jsonplaceholder.typicode.com/albums/1
Code language: Python (python)
It’ll return JSON data in the following format:
{
"userId": 1,
"id": 1,
"title": "quidem molestiae enim"
}
Code language: Python (python)
Since the requests
module is not a built-in module, you need to install it by running the following pip command:
pip install requests
Code language: Python (python)
Making an API call using the requests module
The following defines a new module called album.py
with a function find_album_by_id()
that returns an album by an id:
import requests
def find_album_by_id(id):
url = f'https://jsonplaceholder.typicode.com/albums/{id}'
response = requests.get(url)
if response.status_code == 200:
return response.json()['title']
else:
return None
Code language: Python (python)
How it works.
First, format the API end-point that includes the id parameter:
url = f'https://jsonplaceholder.typicode.com/albums/{id}'
Code language: Python (python)
Second, call the get()
function of the requests module to get a Response
object:
response = requests.get(url)
Code language: Python (python)
Third, call the json()
method of the response object if the API call succeeds:
if response.status_code == 200:
return response.json()['title']
else:
return None
Code language: Python (python)
The response.json()
returns a dictionary that represents the JSON data.
Creating a test module
We’ll create a test_album.py
test module that tests the functions in the album.py
module:
import unittest
from album import find_album_by_id
class TestAlbum(unittest.TestCase):
pass
Code language: Python (python)
Mocking the requests module
The find_album_by_id()
function has two dependencies:
- The
get()
method of therequests
module - The
Response
object returned by theget()
function.
So to test the find_album_by_id()
function, you need to:
- First, mock the requests module and call the
get()
function (mock_requests
) - Second, mock the returned response object.
In other words, the mock_requests.get()
returns a mock response object.
To mock the requests module, you can use the patch()
function. Suppose that the mock_requests
is a mock of the requests
module.
The mock_requests.get()
should return a mock for the response. To mock the response, you can use the MagicMock
class of the unittest.mock
module.
The following shows how to test the find_album_by_id()
using the test_find_album_by_id_success()
test method:
import unittest
from unittest.mock import MagicMock, patch
from album import find_album_by_id
class TestAlbum(unittest.TestCase):
@patch('album.requests')
def test_find_album_by_id_success(self, mock_requests):
# mock the response
mock_response = MagicMock()
mock_response.status_code = 200
mock_response.json.return_value = {
'userId': 1,
'id': 1,
'title': 'hello',
}
# specify the return value of the get() method
mock_requests.get.return_value = mock_response
# call the find_album_by_id and test if the title is 'hello'
self.assertEqual(find_album_by_id(1), 'hello')
Code language: Python (python)
How it works.
First, patch the requests
module as the mock_requests
object:
@patch('album.requests')
def test_find_album_by_id_success(self, mock_requests):
# ...
Code language: Python (python)
Second, mock the response of the get()
function using the MagicMock
class. In this test method, we specify the status code 200 and return_value
of the json()
function as a hard-coded value:
mock_response = MagicMock()
mock_response.status_code = 200
mock_response.json.return_value = {
'userId': 1,
'id': 1,
'title': 'hello',
}
Code language: Python (python)
Third, use the mock_response as the return value of the get()
function:
mock_requests.get.return_value = mock_response
Code language: Python (python)
Finally, test if the title of the album is equal to the one that we specified in the return_value
of the mock_response
:
self.assertEqual(find_album_by_id(1), 'hello')
Code language: Python (python)
Run the test:
python -m unittest -v
Code language: Python (python)
Output:
test_find_album_by_id_success (test_album.TestAlbum) ... ok
----------------------------------------------------------------------
Ran 1 test in 0.001s
OK
Code language: Python (python)
By using the same technique, you can also test the find_album_by_id()
function in the failed case:
import unittest
from unittest.mock import MagicMock, patch
from album import find_album_by_id
class TestAlbum(unittest.TestCase):
@patch('album.requests')
def test_find_album_by_id_success(self, mock_requests):
# mock the response
mock_response = MagicMock()
mock_response.status_code = 200
mock_response.json.return_value = {
'userId': 1,
'id': 1,
'title': 'hello',
}
# specify the return value of the get() method
mock_requests.get.return_value = mock_response
# call the find_album_by_id and test if the title is 'hello'
self.assertEqual(find_album_by_id(1), 'hello')
@patch('album.requests')
def test_find_album_by_id_fail(self, mock_requests):
mock_response = MagicMock()
mock_response.status_code = 400
mock_requests.get.return_value = mock_response
self.assertIsNone(find_album_by_id(1))
Code language: Python (python)
Output:
test_find_album_by_id_fail (test_album.TestAlbum) ... ok
test_find_album_by_id_success (test_album.TestAlbum) ... ok
----------------------------------------------------------------------
Ran 2 tests in 0.002s
OK
Code language: Python (python)
Summary
- Use the
patch()
function to mock the requests module (mock_requests
) - Use the
MagicMock
to mock the response returned by themock_requests.get()
function.