Mocking in Python Unit Testing with unittest

Python

Mocking in Python is a powerful technique used in unit testing to isolate the code being tested from its dependencies. It allows us to simulate the behavior of complex, real (non-deterministic) systems in order to test our code in isolation. In this article, we will discuss how to use mocks with unittest in Python for a hypothetical InvoicesAPI class that interacts with an external HTTP service.

Table of Contents

The InvoicesAPI Class

Let’s assume we have the following simple InvoicesAPI class:


class InvoicesAPI:
    def __init__(self, http_client):
        self.http_client = http_client

    def get_invoices(self, search_params):
        response = self.http_client.get('/api/invoices', params=search_params)
        return response.json()

This class uses an HttpClient to make HTTP requests and retrieve invoices based on the provided search parameters. The actual implementation of this class might involve more complex logic, but for simplicity’s sake, let’s assume it only makes a GET request with the given search parameters.

Mocking HttpClient

To test InvoicesAPI without actually making HTTP requests to an external service, we can use Python’s built-in unittest.mock module. This module provides a way to replace parts of your system under test and make assertions about how they have been used.

Here is an example of how you might write a unit test for the InvoicesAPI class using mocks:


import unittest
from unittest.mock import Mock
from invoices_api import InvoicesAPI

class TestInvoicesAPI(unittest.TestCase):
    def setUp(self):
        self.http_client = Mock()
        self.invoices_api = InvoicesAPI(self.http_client)

    def test_get_invoices(self):
        # Arrange
        search_params = {'customer': 'John Doe'}
        expected_response = [{'invoice_id': 1}, {'invoice_id': 2}]
        
        self.http_client.get.return_value.json.return_value = expected_response

        # Act
        result = self.invoices_api.get_invoices(search_params)

        # Assert
        self.http_client.get.assert_called_once_with('/api/invoices', params=search_params)
        self.assertEqual(result, expected_response)

In this test, we first create a Mock object for the HttpClient and pass it to our InvoicesAPI instance in the setUp method.

We arrange by setting up the expected response from the HTTP request and the search parameters for our test case. In the act step, we call the get_invoices method of our InvoicesAPI instance. Finally, in the assert step, we verify that the mocked HttpClient was called with the correct arguments and returned the expected response.

Conclusion

Mocking is a powerful tool for unit testing in Python. It allows us to isolate our code from its dependencies and simulate their behavior. By using mocks, we can write tests that are fast, reliable, and easy to maintain. In this article, we discussed how to use the unittest.mock module to mock out dependencies in a hypothetical InvoicesAPI class.

To top