Python > Quality and Best Practices > Testing > Test Fixtures and Mocking
Mocking external dependencies with unittest.mock
This snippet demonstrates how to use the `unittest.mock` library to mock external dependencies in your tests. Mocking allows you to isolate the code under test and avoid relying on external resources that may be unavailable or unreliable.
Basic Mocking Example
This example shows how to mock the `get_data_from_api` function using `unittest.mock.patch`. The `@patch` decorator replaces the original function with a mock object for the duration of the test. Inside the test function, you can configure the mock object to return a specific value, and then call the function under test. You can then use `assert_called_once` (or other `assert_called` methods) to verify that the mock was called as expected, and assert that the result of the function under test is as expected.
import unittest
from unittest.mock import patch
# Assume this is an external API call
def get_data_from_api():
# This would normally make an API request
return {"data": "real data"}
def process_data():
data = get_data_from_api()
return data["data"]
class TestProcessData(unittest.TestCase):
@patch('__main__.get_data_from_api') # replace with your module name
def test_process_data(self, mock_get_data):
# Configure the mock to return a specific value
mock_get_data.return_value = {"data": "mocked data"}
# Call the function under test
result = process_data()
# Assert that the mock was called
mock_get_data.assert_called_once()
# Assert that the result is as expected
self.assertEqual(result, "mocked data")
if __name__ == '__main__':
unittest.main()
Concepts Behind Mocking
Mocking is a technique used to isolate the code under test from its dependencies. Key concepts include: * Mock Object: A stand-in object that mimics the behavior of a real object. * Stubbing: Configuring the mock object to return specific values or raise specific exceptions. * Assertion: Verifying that the mock object was called with the expected arguments. By mocking external dependencies, you can ensure that your tests are fast, reliable, and independent of external factors.
Real-Life Use Case
Imagine you're testing a function that sends an email. You wouldn't want to actually send an email during testing, as this could have unintended consequences. Instead, you could mock the email sending function to verify that it was called with the correct arguments.
Best Practices
Here are some best practices for using `unittest.mock`: * Mock only what you need to: Avoid mocking internal implementation details. Focus on mocking external dependencies. * Use descriptive names: Use clear and descriptive names for your mock objects. * Verify interactions: Use assertions to verify that the mock objects were called with the expected arguments. * Clean up mocks: Ensure that mocks are properly cleaned up after each test to avoid interference between tests. `patch` context manager takes care of this automatically.
When to Use Them
Use mocking whenever you need to isolate the code under test from its dependencies. This is especially important when testing code that interacts with: * Databases * External APIs * File systems * Network connections.
Alternatives
While `unittest.mock` is a powerful mocking library, other options exist, such as `pytest-mock` (a pytest plugin that provides a convenient way to use mocking). `pytest-mock` often provides a cleaner and more concise syntax, but `unittest.mock` is part of the standard library and therefore doesn't require any additional dependencies.
Pros
* Isolation: Mocks isolate the code under test from its dependencies. * Speed: Mocks can significantly speed up your tests by avoiding slow external operations. * Reliability: Mocks make your tests more reliable by eliminating dependencies on external resources.
Cons
* Complexity: Mocking can add complexity to your test suite if not used carefully. * Over-mocking: Mocking too much can lead to tests that don't accurately reflect the behavior of the real system.
FAQ
-
How can I mock a class?
You can use `unittest.mock.patch.object` to mock a specific attribute of a class. -
How can I mock a method?
You can use `unittest.mock.patch.object` to mock a method of a class. This is similar to mocking an attribute, but you'll need to configure the mock object to return a callable that mimics the behavior of the method.