Getting Started With Python unittest.mock Library

Ini Arthur

Posted On: January 15, 2025

view count59415 Views

Read time19 Min Read

Testing software applications involves dealing with external dependencies like APIs, databases, or third-party services. However, these dependencies can sometimes present challenges, such as slow test execution, inconsistent test results, and other factors.

In such scenarios, the mocking mechanism can simulate these dependencies, allowing you to isolate software application logic and write efficient and reliable test scripts. Programming languages like Python further simplify this process with libraries like unittest.mock. Python unittest.mock library allows you to create mock objects that mock certain external APIs and dependencies.

In this blog, we will learn how to use the built-in Python unittest.mock library in automated testing.

What Are Mocks?

A mock object mimics the behavior of a real object that is the subject of a test in isolation. Mocks or mock objects are used when it is impractical to include real objects or external dependencies during the test execution (unit testing).

The essence of a mock test is to isolate the object under test from its dependencies to validate that it works as expected when called or triggered. It allows testing to be completed in a shorter period, even without external dependencies, in a developer-controlled environment.

Scenarios where mock tests are used include testing codebase with dependencies such as external APIs, databases, and other third-party web services. An example will be an online store that uses a third-party payment gateway to process customers’ payments. A tester will mock the payment API in the test environment to simulate pending, failed or successful transactions.

database

What Is Python unittest.mock Library?

Python unittest.mock library is used for creating mock objects when it becomes impractical to test real objects. At its core, Python unittest.mock library provides a Mock class for creating mock objects. This Mock class simulates functions, libraries and many other external dependencies. After creation, it sets attributes and returns values for the mock objects. You can assert which method or attribute was called, how many times it was called and with which specific argument.

The Python unittest.mock library provides the patch() decorator, which is used for temporarily patching modules, classes, and specific attributes within a given test suite. It can also be used as a context manager to control the scope of the object being mocked during testing. Objects are cleaned up after the context manager’s scope is exited.

MagicMock is part of the Python unittest.mock library. It is a subclass of the Mock class that implements most of Python’s magic methods. Unlike the Mock class, MagicMock can be used without configuring magic methods. The AsyncMock is another subclass of Mock, a specialized class for mocking asynchronous functions. AsyncMock makes it easy to test Python’s async functions and coroutines, ensuring that mocked objects are awaited.

Key Components of Python unittest.mock Library

Here are the components of the Python unittest.mock library that lets you isolate your code for testing by replacing dependencies, ensuring reliable and independent test results.

  • Mock Class: Use this to create mock objects for replacing real components in your tests. It dynamically creates attributes and methods as needed.
  • Syntax:

  • MagicMock Class: A subclass of Mock that comes with built-in magic methods (e.g., __add__, __getitem__). Use it to mock objects requiring special operations like arithmetic or item access.
  • Syntax:

  • AsyncMock Class:Specifically for mocking asynchronous functions or objects. It supports await and tracks async calls for testing async code.
  • Syntax:

  • patch() Decorator: Temporarily replace an object during a test. Use it as a decorator or context manager to mock dependencies without altering your code permanently.
  • Syntax:

Setting Up Python unittest.mock Library

In older versions of Python, the mock module was a standalone library. From version 3.3, the Python unittest.mock library was added to the standard library. If you use version < 3.3 of Python, you can install mock via the following command:

However, we’ll use unittest.mock as part of the Python standard library. Let’s outline the steps to set up the basic structure of a Python test using unittest and mock.

  1. Import the Mock and MagicMock classes or the patch() decorator function from unittest.mock library where necessary as follows:
  2. The unittest module uses object-oriented class-based principles for creating test cases. The test class inherits from the unittest.TestCase.
  3. A typical test class will look like this:

  4. Next, we use the Mock and MagicMock classes or the patch() decorator function as necessary to create mocks. We’ll elaborate on this step in the next section.

Creating Mock Objects

Mocks can be used to represent real objects in your test code. They are also callable, and attributes are created as new mocks when accessed.

  1. The Mock and MagicMock classes can be used interchangeably, but for most of this blog, we will create mock objects using the MagicMock class.
  2. After creating a mock object, we can set a return value for its method, an attribute and value and a side effect.
  3. Use the patch() decorator to patch objects in a library or class, and the patching is done within the scope of the function. The Python mock library provides a sentinel object for creating placeholder objects.
  4. The patch() decorator replaces the object targeted in ‘package.module.ClassName.attribute’ with a unique placeholder value sentinel.attribute during the test.

    A module or class is also unpatched automatically. The patch() can be used with the with statement to create a context manager. This applies the patch to the scope of the with statement. As a context manager, the patched object is bound to the name after as and only accessible within the scope.

    Here is an example of mocking a class with the patch() method as a context manager:

    The patch() method is used as function decorator:

  5. Assertion methods in mock objects verify whether they were called, how often, and whether the correct argument was passed in when called.
  6. Use the asyncio module to await the AsyncMock object to mimic an asynchronous function. A some_async_method is created, and its return value is set to An async mock object. The async_mock object method is called and awaited within an asynchronous context main(), and the result is printed.

How to Use Python unittest.mock Library?

To demonstrate the use of the Python unittest.mock library, we’ll cover examples of creating mocks to mimic an API response, form submission and the Selenium browser automation framework’s explicit wait processes.

First, we’ll write a normal test case without mocks and then refactor it with mock objects. Before we begin, we’ll set up a remote connection to test on a cloud testing platform such as LambdaTest.

LambdaTest is an AI-powered test execution platform that lets you perform automation testing with Python due to its cloud-based infrastructure, seamless integration with Python testing frameworks like pytest and unittest, and support for parallel testing across diverse environments.

To get started, check out this documentation to run Python unittest tests on LambdaTest.

We will also create a simple fixture class that will be used throughout each of our test cases. Copy your Username and Access Key from your LambdaTest account. Then, create a file for your LambdaTest automation capabilities and fixture class. You can generate capabilities from the LambdaTest Automation Capabilities Generator.

Now, update the fixture file with the code below:

Filename: mock_fixtures.py

gituhb

Code Walkthrough:

Import all needed modules and dependencies. Retrieve the LambdaTest Username and Access Key from the environment variables.

Now configure Chrome browser options and set LambdaTest Selenium capabilities. You can generate them using the Automation Capabilities Generator. Set values for the LambdaTest capabilities dictionary lt_options keys like username, access, build, etc.

Define a BaseTestCase class, which will inherit other test sub-classes. After that, define a setUp method that gets executed before any test case. A driver object is instantiated using the webdriver.Remote() constructor which creates a remote connection to LambdaTest.

The webdriver.Remote() takes command_executor and options as arguments. The hub URL for command_executor takes a combination of username and access-key as arguments.

Define a tearDown method that gets executed after each test case. The tearDown method cleans the resources by quitting the driver instance.

Mocking an API Response

In this section, we’ll show how to mock an API response. For this example, we’ll use the JSON placeholder user endpoint. We’ll also mock the Selenium WebDriver, the response object and other dependencies.

It is important to note that mocking dependencies and real objects should only be done in testing environments, while the actual dependencies should be used when in a production environment.

Test Scenario:

  1. Access the JSON placeholder user endpoint.
  2. Locate the pre-tag element that contains the JSON data.
  3. Extract users’ JSON data and parse.
  4. Convert JSON string to Python dictionary.
  5. Make assertion statements to verify that returned data matches expectations.

Implementation: A mocked test case for the API success response will look like this:

Filename: tests/test_mock_api_response.py

Outside a test environment where mocks are used for testing, a real test case will look like this:

Filename: tests/test_api_response.py

Code Walkthrough:

Create mock objects mock_by and mock_webdriver_wait from the By and WebDriverWait classes using the patch() decorator. The patch() decorator mocks only the By and WebDriverWait classes imported in the api_response.py file, not the entire global namespace.

Define a method, test_fetch_users_api(), where our mocked API response will be tested. In the method definition, the mocked objects mock_by and mock_webdriver_wait are passed as parameters.

Create a mock object, mock_driver, to mimic the remote Selenium WebDriver. Another mock object, mock_pre_element, is created for the DOM element that holds the users’ JSON data. A JSON string is assigned to the mock_pre_element.text attribute.

Now, create a mock_wait_instance mock with a method until and a return value of mock_pre_element assigned to it. Assign the return value for mock_webdriver_wait to mock_wait_instance. These mock objects created mimic Selenium wait and the DOM pre element being waited for.

Call the fetch_users_api function passing mock_driver as an argument. The function returns a list of users when called. Post that, call the assert_called_once_with() on the get method to verify it was called only once with the correct URL.

Test Execution:

Run the below-given command to run the test:

You can view your test results from the LambdaTest Web Automation dashboard:

unit test

Mocking a Form Submission Process

You can mock the form submission process to validate that the web application correctly collects, processes, and sends form data without needing a real browser or front-end setup. It allows you to verify that the correct data was captured and sent to the server.

Test Scenario:

  1. Navigate to the Form Submission Demo page of the LambdaTest Selenium Playground.
  2. Locate the title input and description textarea fields.
  3. Populate the title input and description area fields with the provided title and description.
  4. Locate the submit button and click.
  5. Assert that the page title returned matches the expected page title.

Implementation: A mocked test case for the submit_form function looks like this:

Filename: tests/test_mock_submit_form.py

A real test case without mock will look like this:

Filename: test/test_submit_form.py


Code Walkthrough:

Use the patch() decorator to mock the webdriver.Remote class. The mock_fixtures.webdriver.Remote string defines the path where the webdriver.Remote class was imported from. The string indicates where the Remote WebDriver is used. The patch() decorator creates a mock object mock_webdriver.

Create a mock_driver mock object from the MagicMock() class. Set the return_value of mock_webdriver to mock_driver. It means that the patched webdriver.Remote class will return the mock object mock_driver.

Call the submit_form function under test with the mocked webdriver.Remote instance and other arguments. It means that the operation is done entirely on the mocked object and not a real browser.

Make assertion calls to validate that the code works as expected. As the code snippet shows, the assert_any_call() method asserts that the mock has been called with the specified arguments. The assert_called_once_with() method asserts that the mock was called once.

Test Execution:
Run the below-given command to run the test:

You can view your test results from the LambdaTest Web Automation dashboard:

web

Mocking the Selenium Explicit Wait

The Selenium framework is well-known for its implicit and explicit waiting strategies. These strategies are mostly deployed when interacting with websites that have dynamic content and elements that may not be available until an action is triggered.

In this section, we’ll explore how to mock the Selenium explicit wait strategy. We will also patch the expected condition module EC and the WebDriverWait class. The mocks will simulate browser interactions without actually opening a browser or waiting for real elements.

Test Scenario:

  1. Navigate to the LambdaTest eCommerce Playground page.
  2. Locate the My account on the navigation menu and click.
  3. Wait for the new page until it loads.
  4. Wait for the target Login component to load.
  5. Retrieve the text content of the element.
  6. Assert that the text returned matches the expected text Login.

Implementation: The explicit wait test case will look like this when mocked:

Filename: tests/test_selenium_wait.py

Refactored, the above test case will look like the code snippet below without mocks being implemented.

Filename: tests/test_mock_selenium_wait.py

Code Walkthrough:

Mock the WebDriverWait class and the expected condition (EC) module with the patch function decorator.

The patch() decorator during the test replaces the WebDriverWait class and the EC module temporarily with mock objects. EC becomes mock_visibility_of_element_located, and WebDriverWait becomes mock_WebDriverWait, respectively, as mock objects.

Mock other dependencies in the test_wait_for_button_element() method. First, create a mock object mock_driver that represents the Selenium WebDriver. Another mock object, mock_element, is created for the target element. A text attribute of the mock_element is set to Login. The return value for the patch EC module mock_visibility_of_element_located is set to mock_element.

Again, create a mock object mock_wait_instance from MagicMock. Set the wait instance’s mock_wait_instance.until.return_value to the earlier created mock_element. Also, set mock_wait_instance as the return value for mock_WebDriverWait.

The above mock objects simulate the WebDriverWait instance’s waiting behavior until the targeted element is visible and the text within it is captured.

Instantiate the ExplicitWait class. After instantiating the ExplicitWait class with the mock object mock_driver, call the explicit_wait.wait_for_button_element() method. It will trigger mocked objects to simulate the behavior of the real object they represent.

Make assertion calls to validate the behavior of mock objects. We can proceed to make assertion calls on mock objects. The mock_WebDriverWait.assert_called_once_with(), asserts that the mock object was called only once with the arguments mocker_driver and a timeout value of 10 seconds.

The assert_called_once_with() method is also called on the mock_visibility_of_element_located mock object with the correct argument for XPATH. Assert returned element text matches the expectation.

Test Execution:

Run the below-given command to run the test:

You can view your test results from the LambdaTest Web Automation dashboard:

Cases of Mocking

Real-World Use Cases of Mocking

Mocking a test is a widely adopted practice in automated testing. It is used in various cases to isolate certain software components or external dependencies in testing or staging environments.

We’ll highlight some popular real-world use cases below:

python

  • Mocking API Responses: During the development phase, there are instances when data needs to be fetched from a remote API service. However, when the developer decides to test a feature that uses this remote API, the API may not be available. Therefore, it becomes increasingly important to carry out testing even without the API’s availability.
  • It provides a use case for mocking the software feature to ensure it works as expected. The API response will be mocked to test success scenarios, errors or timeouts.

  • Mocking Database Operations: We can also use mocks to mimic database operations such as fetching, updating and deleting records. Interacting with a live database can be too much overhead and generally slow testing. To test that our function interacts with the database as expected, we can mock this process.
  • To mimic the database’s behavior, we mock the database connection and the different queries to it. This way, we can verify that our function(s) work as expected when interacting with the database.

  • File I/O Operations: File input/output operations are generally regarded as resource-intensive and, in most cases, block requests. System calls like read() and write() methods can delay the operation until it is complete before control is returned to the application.
  • In this use case, mocks are implemented to avoid delays resulting from reading, writing and deleting files. With mocks, file I/O operations are simulated to test components of the software application.

Best Practices for Implementing Mocking

Mocking is essential when performing different types of software testing. Mocks produce faster and better tests by reducing reliance on external dependencies that may be unavailable during testing.

However, mocking tests should only be used when necessary. For better and more effective results, here are a few best practices to follow when mocking.

  • Avoid Overusing Mocks: Too many mocks in your test scripts can bloat your codebase and make tests fragile. Over-mocking increases dependency on mocked components, making the tests harder to maintain.
  • Limit Mocks to the Right Environment: Use mocks only in the development and testing phases—not in production. Write loosely coupled code to make mocking easier, as tightly coupled code is harder to isolate.
  • Balance Mocks and Real Services: Only mock components are prone to failure due to external dependencies. Keep the rest of the code unmocked for more realistic system behavior, and switch between mocks and real services using tools like feature flags or environment variables.
  • Keep Mocks Simple: Avoid creating overly complex mock objects. Simplicity ensures maintainability and aligns with the purpose of mock tests.
  • Use Real Data When Possible: To simulate realistic system behavior, test with real data instead of relying solely on dummy data.
  • Avoid Hardcoding Mock Values: Configure mock objects dynamically to ensure flexibility and realistic responses.
  • Understand Method Behavior: Ensure you fully understand the methods you’re mocking, including their signatures and expected behavior, to prevent inaccurate test results.

Conclusion

Mocking helps you carry out tests without relying on dependencies that may be unavailable at the time of testing. We create a mock object to simulate the behavior of a real-world object it temporarily replaces during tests.

Python provides the unittest.mock module for creating mocks without a Python codebase. Mocks are made using either the Mock and MagicMock classes or the patch() decorator. After successfully creating mock objects, make assertion calls to verify that they behave as expected.

Mocking makes testing faster. However, you should avoid over-mocking and only use mocks when necessary.

Frequently Asked Questions (FAQs)

How do mocks help in unit testing?

Mocks are used in unit testing to isolate the unit of code being tested by replacing its dependencies with mock objects. This ensures that the test focuses solely on the functionality of the unit without being affected by external systems like databases, network calls, or APIs.

What is the side_effect attribute in mock objects?

The side_effect attribute allows you to specify a function or an exception to be raised when a mock object is called. It provides more control over the behavior of the mock, enabling the simulation of different scenarios, such as errors or varying return values based on input.

What is the purpose of assert_called_with() in mock testing?

The assert_called_with() is a method used to verify that a mock object was called with specific arguments. It ensures that the mock was interacted with as expected, making it useful for validating the behavior of the code under test.

Can I mock asynchronous functions using the Python unittest.mock library?

Yes, Python unittest.mock library provides the AsyncMock class, which allows you to mock asynchronous functions (i.e., those that use async def and await). It behaves similarly to Mock, but supports async-specific features like await and assert_awaited_with() method.

Citations

Author Profile Author Profile Author Profile

Author’s Profile

Ini Arthur

Iniubong Arthur is a dedicated individual with strong critical thinking, design thinking, and software engineering skills. His current focus is on developing software solutions in Django, Flutter & React that solves real-world problems.

Blogs: 3



linkedintwitter

Test Your Web Or Mobile Apps On 3000+ Browsers

Signup for free