Python > Testing in Python > Mocking and Patching > Patching Objects and Functions
Patching a Function's Return Value
This example demonstrates how to use unittest.mock.patch
to replace a function's return value during a test. This technique is crucial for isolating code units and simulating specific outcomes during testing.
Concepts Behind Patching Function Return Values
Patching a function's return value allows you to control what a function returns when it is called during a test. This is valuable when you need to simulate different scenarios, such as handling errors, simulating external API responses, or testing code that relies on specific function outputs. By replacing the function with a mock object, you can dictate its return value without actually executing the original function's logic.
Code Example: Patching a Function's Return Value
This code defines a function external_api_call
that simulates a call to an external API and returns a string. The process_data
function calls external_api_call
and processes the returned data. The TestProcessData
class contains two test methods. The first test method, test_process_data_with_mocked_api
, uses the @patch
decorator to replace external_api_call
with a mock object. The mock object's return_value
is set to 'Mocked API Response'
. When process_data
is called, it uses the mocked external_api_call
, and the result is asserted to be 'Processed: Mocked API Response'
. The second test method, test_process_data_without_mock
, calls process_data
without any mocking, so the original external_api_call
is used, returning 'Processed: Real API Response'
. The patch target is a string that identifies the full path to the function to be patched. The mocked function is passed as an argument to the test method.
import unittest
from unittest.mock import patch
def external_api_call():
# Simulate a call to an external API
return 'Real API Response'
def process_data():
data = external_api_call()
return f'Processed: {data}'
class TestProcessData(unittest.TestCase):
@patch('__main__.external_api_call')
def test_process_data_with_mocked_api(self, mock_api_call):
mock_api_call.return_value = 'Mocked API Response'
result = process_data()
self.assertEqual(result, 'Processed: Mocked API Response')
def test_process_data_without_mock(self):
result = process_data()
self.assertEqual(result, 'Processed: Real API Response')
if __name__ == '__main__':
unittest.main()
Real-Life Use Case
Consider a function that interacts with a database. During testing, you don't want to actually hit the database, as this can be slow and unreliable. By patching the database interaction function, you can simulate the database's behavior and ensure that your code handles different database responses correctly.
Best Practices
return_value
: To set the return value of a mock.mock_api_call.assert_called_once()
) to verify that the mocked function was called as expected.
Interview Tip
Discuss the trade-offs between mocking and integration testing. Explain how mocking allows you to focus on the logic within a specific function or class, while integration testing verifies the interactions between different components. Be prepared to describe scenarios where mocking is essential and when integration tests are more appropriate.
When to Use Patching Function Return Values
Use patching function return values when:
Alternatives
Alternatives to patching function return values include:
Pros
Cons
FAQ
-
Can I patch a function that's called multiple times with different arguments?
Yes, you can usemock_api_call.side_effect
to define a function that returns different values based on the input arguments. This allows you to simulate more complex scenarios. -
How do I verify that the patched function was called with the correct arguments?
Use mock object assertions such asmock_api_call.assert_called_with(expected_argument)
ormock_api_call.call_args
to inspect the arguments passed to the mocked function.