Originally published at recca0120.github.io
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:
def sum(a, b):
return a + b
helloworld.py:
from utils import sum
def main():
return sum(1, 2)
Writing a test to mock sum:
from unittest.mock import patch
def test_main():
with patch('utils.sum') as mocked:
mocked.return_value = 5
assert main() == 5 # Fails! AssertionError: 3 != 5
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:
After patch('utils.sum'):
utils.sum βββββββ MockObject β patch replaced this
helloworld.sum βββ <original> β this is untouched; main() uses this
The Fix
Patch the module that uses the function β the module under test:
def test_main():
with patch('helloworld.sum') as mocked: # patch here instead
mocked.return_value = 5
assert main() == 5 # passes
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:
[!IMPORTANT]
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
# utils.py
def sum(a, b):
return a + b
# helloworld.py
from utils import sum
def main():
return sum(1, 2)
# test_helloworld.py
from unittest.mock import patch
from helloworld import main
def test_main_wrong_patch():
# Wrong: patches utils.sum, but helloworld.sum is unaffected
with patch('utils.sum') as mocked:
mocked.return_value = 5
result = main()
assert result == 5 # AssertionError: 3 != 5
def test_main_correct_patch():
# Correct: patches the binding in the module that uses it
with patch('helloworld.sum') as mocked:
mocked.return_value = 5
result = main()
assert result == 5 # passes
When Both Functions Are in the Same Module
# app.py
def sum(a, b):
return a + b
def main():
return sum(1, 2)
# test_app.py
with patch('app.sum') as mocked:
mocked.return_value = 5
assert main() == 5 # passes
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.
References
United States
NORTH AMERICA
Related News
What Does "Building in Public" Actually Mean in 2026?
19h ago
The Agentic Headless Backend: What Vibe Coders Still Need After the UI Is Done
19h ago
Why Iβm Still Learning to Code Even With AI
21h ago
I gave Claude a persistent memory for $0/month using Cloudflare
1d ago
NYT: 'Meta's Embrace of AI Is Making Its Employees Miserable'
1d ago