0
0
PytestHow-ToBeginner ยท 3 min read

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'): replaces function in module.
  • 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_effect or setting it incorrectly, leading to unexpected test behavior.
  • Using return_value when you need side_effect to 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 patch with the exact import path where the function is used.
  • Set side_effect to simulate exceptions or multiple return values.
  • Use pytest.raises to assert exceptions from side effects.
  • Check mock.call_count to 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.