Open In App

Mocking external APIs in Python

Last Updated : 08 Jun, 2023
Improve
Improve
Like Article
Like
Save
Share
Report

Consider yourself developing software that needs an external API as a dependency and while testing we found that the API is not functional for some reason. As we know testing is one of the most critical phases in SDLC (Software Development Life Cycle) and without the API dependency, testing could not be performed. We have a few solutions like waiting for the API to become functional or making our own API.

Now both of the solutions are very time and resource consuming which could be disastrous for an organization if there could be a way to mimic the behaviour of the API without using the actual API now when mocking API can be used.

Here when mocking external services could be a better solution in this we make a mock which is a fake object that we construct to look and act like the real one. We swap the actual object with a mock and trick the software into thinking that the mock is real. By this developers can test the software or code without relying on the external service, especially when the external services are down.

Prerequisites –

To understand the article entirely the following prerequisite is expected:

  1. A good foothold in Python Programming language.
  2. Familiarity with Python unit test module.
  3. Basics of software testing in Python.

How to Mock External API in Python –

The unit test is a framework to perform unit testing in Python just like JUnit in Java. Now unit test consists of a library called the unit test. mock that is used to replace parts of your system under test with mock objects and make assertions about how they have been used.

Developers can make a fake mock object that mimics the behaviour of a real object and perform the testing of the code in an isolated environment.

Mocking External API Demonstration –

As we covered an overview of how mocking external API could be achieved in Python now let us see it in action through the following demonstration.

Python3




import requests
import json
  
# get_data() is a function that makes a request to an external api and returns the data in json format
def get_data():
    response = requests.get('https://jsonplaceholder.typicode.com/todos/1')
    data = json.loads(response.text)
    return data
  
# main() is a function that calls get_data() and prints the data
def main():
    print(get_data())
  
if __name__ == '__main__':
    main()


Output:

Output

In the above code we are using the requests modules get function to make a GET request to the specified API, serialize its response to JSON and print it.

Now let’s mock the API in the above code –

Python3




# TestGetData is a class that contains a test_get_data() 
# method that tests the get_data() function using the mock library
  
class TestGetData(unittest.TestCase):
    @patch('main.get_data')
    def test_get_data(self, mock_get_data):
        """
        Test that get_data() returns the correct data 
        demonstrating the use of the mock library
        """
  
        mock_data = {'userId': 1, 'id': 1,
                     'title': 'delectus aut autem', 'completed': False}
  
        mock_get_data.return_value = Mock()
  
        mock_get_data.return_value.json.return_value = mock_data
        mock_get_data.return_value.status_code = 200
  
        result = get_data()
  
        self.assertEqual(result, mock_data)


Now the idea is to use the patch function from the mock library by adding the patch() as a decorator in the test function. In the test function itself, we pass a parameter mock_get_data, and in the body of the function we set the expected response data with the status code.

So what actually happens when the test run? first, let’s understand how the requests module works. When we make HTTP GET request using the requests module it interacts with the server and returns an HTTP response in form of a response object. Now by using the patch decorator in the test function it will replace the target function get_data() in this case with the mock one.

The mock function acts the way the function expects for example the `get_data` function is said to return a successful response when the response status code is 200 and the response data is non-empty data which is a mock data returned using mock_get_data.return_value.json.return_value.

Code:

Python3




# mocking a external api in python
import requests
import json
import unittest
from unittest.mock import patch, Mock
  
# get_data() is a function that makes a request to an 
# external api and returns the data in json format
  
  
def get_data():
    response = requests.get('https://jsonplaceholder.typicode.com/todos/1')
    data = json.loads(response.text)
    return data
  
  
# TestGetData is a class that contains a test_get_data() 
# method that tests the get_data() function using the mock library
  
  
class TestGetData(unittest.TestCase):
    @patch('main.get_data')
    def test_get_data(self, mock_get_data):
        """
        Test that get_data() returns the correct data demonstrating the 
        use of the mock library
        """
  
        mock_data = {'userId': 1, 'id': 1,
                     'title': 'delectus aut autem', 'completed': False}
  
        mock_get_data.return_value = Mock()
  
        mock_get_data.return_value.json.return_value = mock_data
        mock_get_data.return_value.status_code = 200
  
        result = get_data()
  
        self.assertEqual(result, mock_data)
  
  
if __name__ == '__main__':
    unittest.main(argv=['first-arg-is-ignored'], exit=False)


Output:

Output



Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads