patch as decorator and context manager
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
- Allows testing code that talks to databases or APIs without actually calling them.
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
- Patching the wrong location: You must patch where the object is looked up, not where it is defined. If `moduleA` imports a function from `moduleB`, patch it in `moduleA`.
Recall questions
- Explain `patch` in your own words, as if to a classmate.
- What is the difference between using `patch` as a decorator and using it as a context manager?
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