Python Mock Requests

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/1Code 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 requestsCode 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 NoneCode 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 NoneCode 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): passCode language: Python (python)

Mocking the requests module

The find_album_by_id() function has two dependencies:

  • The get() method of the requests module
  • The Response object returned by the get() 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_responseCode 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 -vCode language: Python (python)

Output:

test_find_album_by_id_success (test_album.TestAlbum) ... ok ---------------------------------------------------------------------- Ran 1 test in 0.001s OKCode 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

Comments

Leave a Reply

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