How to Mock Side Effects in pytest: Simple Guide
To mock side effects in
pytest, use unittest.mock.patch to replace the function causing the side effect with a mock. You can set the side_effect attribute on the mock to simulate exceptions or custom behavior during tests.Syntax
Use unittest.mock.patch as a decorator or context manager to replace the target function. The side_effect attribute on the mock can be set to a function, an exception, or an iterable to simulate different behaviors.
@patch('module.function'): replacesfunctioninmodule.mock.side_effect = Exception(): makes the mock raise an exception when called.mock.side_effect = [value1, value2]: returns values in sequence on calls.
python
from unittest.mock import patch @patch('module.function') def test_example(mock_function): mock_function.side_effect = Exception('error') # test code here
Example
This example shows how to mock a function that sends an email to avoid actually sending emails during tests. The mock simulates a side effect by raising an exception on the second call.
python
from unittest.mock import patch import pytest # Function with side effect def send_email(address): print(f"Sending email to {address}") # Imagine this sends an email def notify_users(users): for user in users: send_email(user) @patch('__main__.send_email') def test_notify_users(mock_send): # First call succeeds, second call raises an exception mock_send.side_effect = [None, Exception('SMTP error')] users = ['alice@example.com', 'bob@example.com'] with pytest.raises(Exception) as excinfo: notify_users(users) assert str(excinfo.value) == 'SMTP error' assert mock_send.call_count == 2
Output
PASSED
Common Pitfalls
Common mistakes when mocking side effects include:
- Not patching the correct import path of the function, causing the mock to have no effect.
- Forgetting to set
side_effector setting it incorrectly, leading to unexpected test behavior. - Using
return_valuewhen you needside_effectto simulate exceptions or multiple calls.
python
from unittest.mock import patch import pytest # Wrong patch path example @patch('wrong_module.send_email') # This won't mock the actual function def test_wrong_patch(mock_send): mock_send.side_effect = Exception('error') # This test will not catch the exception as expected # Correct patch path example @patch('__main__.send_email') def test_correct_patch(mock_send): mock_send.side_effect = Exception('error') with pytest.raises(Exception): send_email('test@example.com')
Output
PASSED
PASSED
Quick Reference
Remember these tips when mocking side effects in pytest:
- Use
patchwith the exact import path where the function is used. - Set
side_effectto simulate exceptions or multiple return values. - Use
pytest.raisesto assert exceptions from side effects. - Check
mock.call_countto verify how many times the mock was called.
Key Takeaways
Use unittest.mock.patch to replace functions causing side effects in pytest tests.
Set the mock's side_effect to simulate exceptions or multiple call behaviors.
Always patch the function at the import location used by the code under test.
Use pytest.raises to test for exceptions triggered by side effects.
Verify mock calls with call_count to ensure expected interactions.