pythonunit-testingtestingpython-unittest.mock

Python mock testing and API call locally using it's JSON pre-generated file


I'm currently facing a problem with unit testing a specific function in my code. The function makes an API call, but I want to test it using a locally stored JSON file that represents the response from an older API call. My goal is to ensure that the function correctly reads and processes the JSON file without making actual API requests every time I run the test.

Here's a simplified version of my code:

import json
import unittest
from unittest.mock import patch


class ApiContextRetrieval:
    def __init__(self, search_word):
        self.replication_rule_name = search_word
        self.policy_id = None

        # ...

    def find_policy_id(self):
        replication_policies_list = self.get_replication_policies_list()
        print(replication_policies_list)

        for replication_name in replication_policies_list:
            if replication_name["name"] == self.replication_rule_name:
                self.policy_id = replication_name["id"]
                break

    def get_replication_policies_list(self):
        url = "https://example.com/api/......."
        headers = {"accept": "application/json", "authorization": "Bearer TOKEN"}
        response = requests.get(url, headers=headers)
        replication_policies_json = response.json()
        return replication_policies_json


class TestApiContextRetrieval(unittest.TestCase):
    def setUp(self):
        self.search_word = "rule"
        self.policy_id_of_replication = 50

    @patch("module_name.ApiContextRetrieval.get_replication_policies_list")
    def test_find_policy_id(self, mock_get_replication_policies_list):
        with open("application_jq_used.json") as file:
            replication_policies = json.load(file)

        mock_get_replication_policies_list.return_value = replication_policies

        api_context_retrieval = ApiContextRetrieval(self.search_word)
        api_context_retrieval.find_policy_id()

        print("Policy ID:", api_context_retrieval.policy_id)
        self.assertEqual(api_context_retrieval.policy_id, self.policy_id_of_replication)


if __name__ == "__main__":
    unittest.main()

Solution

  • You can use patch + return_value. Here is an example:

    import unittest
    from unittest.mock import patch, Mock
    
    
    class ApiContextRetrieval:
        def __init__(self, search_word):
            self.replication_rule_name = search_word
            self.policy_id = None
    
        def get_replication_policies_list(self):
            return requests.get('test').json()
    
        def find_policy_id(self):
            replication_policies_list = self.get_replication_policies_list()
    
            for replication_name in replication_policies_list:
                if replication_name['name'] == self.replication_rule_name:
                    self.policy_id = replication_name['id']
                    break
    
    
    class TestApiContextRetrieval(unittest.TestCase):
        def test_find_policy_id(self):
            # read from a file blablabla...
            api_result = [{'id': 1, 'name': 'test'}, {'id': 2, 'name': 'new'}]
            api = ApiContextRetrieval('test')
    
            # patch get_replication_policies_list()
            with patch(
                # change __main__ to your module...
                '__main__.ApiContextRetrieval.get_replication_policies_list',
                return_value=api_result
            ):
                api.find_policy_id()
                self.assertEqual(api.policy_id, 1)
    
        def test_find_policy_id2(self):
            # read from a file blablabla...
            api_result = [{'id': 1, 'name': 'test'}, {'id': 2, 'name': 'new'}]
            api = ApiContextRetrieval('new')
    
            # or you can patch requests.get().json()
            with patch(
                'requests.get',
                return_value=Mock(json=Mock(return_value=api_result))
            ):
                api.find_policy_id()
                self.assertEqual(api.policy_id, 2)
    
    
    if __name__ == '__main__':
        unittest.main()
    

    Result:

    ..
    ----------------------------------------------------------------------
    Ran 2 tests in 0.001s
    
    OK