from utils import sum, then patch('utils.sum') β and the mock never takes effect.
Switch to patch('helloworld.sum') and it works.
This is the most common Python mock mistake. Once you understand why, you won’t hit it again.
Reproducing the Problem
utils.py:
| |
helloworld.py:
| |
Writing a test to mock sum:
| |
main() returns 3, not 5. The mock didn’t take effect.
Why
from utils import sum does one thing: it copies a reference to the utils.sum function object into helloworld’s namespace.
After that import, when helloworld calls sum, it’s using helloworld.sum β not utils.sum.
patch('utils.sum') does replace the sum in the utils module. But helloworld.sum still points at the original function object. It was never touched.
Visualized:
| |
The Fix
Patch the module that uses the function β the module under test:
| |
patch('helloworld.sum') replaces the sum in helloworld’s namespace. That’s the one main() calls, so the mock works.
The Rule: Patch Where It’s Used
This rule is easy to remember:
Patch where the name is used, not where it’s defined.
| Import style | Patch target |
|---|---|
from utils import sum | patch('helloworld.sum') |
import utils | patch('utils.sum') |
With import utils, calling utils.sum(...) looks up sum through the utils module every time β no separate binding is created in helloworld. So patch('utils.sum') works there.
Full Example
| |
| |
| |
When Both Functions Are in the Same Module
| |
| |
Same principle: main() looks up sum in the app namespace, so that’s where you patch.
Summary
Python’s import mechanism creates a separate binding in the importing module. After from X import Y, the module has its own Y β a separate reference from X.Y.
The patch target is always where the call happens, not where the function is defined. Keep that rule in mind and mock-not-working problems essentially disappear.
