patch as decorator and context manager

RoadmapsPython

Overview

**Memorizable line:** `patch` replaces a real object with a fake one during a test, then puts the real one back. It is a tool from the `unittest.mock` library. We use it to stop tests from doing real work, like sending emails or saving to a database. We can use it in two ways. First, as a decorator (using `@`). It applies to the whole test function. ```python from unittest.mock import patch @patch('__main__.send_sms') def test_sms(mock_send): mock_send.return_value = True assert send_sms() == True ``` Second, we can use it as a context manager (using `with`). It applies only to the code block inside it. This is useful when you only want to fake an object for one line. ```python from unittest.mock import patch def test_sms(): with patch('__main__.send_sms') as mock_send: mock_send.return_value = True assert send_sms() == True ``` **Analogy:** Think of an understudy in a play. When the main actor (the real function) is absent, the director (the test) calls the understudy (the mock) to step in. After the scene, the main actor returns.

It keeps tests fast and safe. You do not want a test to send real data over the internet.

Where used: pytest, unittest

Why learn this

Code walkthrough

from unittest.mock import patch

def get_weather():
    return 'Sunny'

def test_weather():
    with patch('__main__.get_weather') as mock_get:
        mock_get.return_value = 'Rainy'
        print(get_weather())

test_weather()

Focus: with patch('__main__.get_weather') as mock_get:

Aha moment

from unittest.mock import patch
def connect(): return 'Real DB'
def test():
    with patch('__main__.connect') as m:
        m.return_value = 'Fake DB'
    print(connect())
test()

Prediction: What does this print?

Common guess: Fake DB

The patch only lasts inside the `with` block. Outside it, the real function is restored, so it prints 'Real DB'.

Common mistakes

Recall questions

Understanding checks

What prints, and why?

offline

The decorator replaces the real `get_status` with a fake one that returns 'offline' for the entire function.

What prints, and why?

online

The context manager puts the real `get_status` back after the `with` block ends, so the real function runs.

Practice tasks

Use patch as a context manager

Given this working test, change it so that `fetch_data` is patched using a context manager (`with patch(...)`) instead of a decorator.

Challenge

Patch a function

Write a test function called `test_payment` that uses the `patch` decorator to mock `charge_card` so it returns True. Call `charge_card` inside.

Continue learning

Previous: Function Decorators

Previous: The 'with' Statement and Resource Management

Return to Python Roadmap