pytest中mock内部函数不生效是因为patch目标必须是被测模块导入时的引用路径,而非定义路径;例如service.py中from utils import fetch_data,则应patch("service.fetch_data")而非"utils.fetch_data"。

pytest 中 mock 内部函数为什么总不生效?
因为 patch 的目标必须是“被测试对象**导入时所引用的位置**”,而不是函数定义的位置。比如你在 utils.py 里写了 def fetch_data():,但测试的是 service.py 中调用它的代码,那就要 patch service.fetch_data,而不是 utils.fetch_data —— 否则 mock 会落空,原函数照常执行。
- 错误示范:
@patch("utils.fetch_data")(在service.py里 import 了from utils import fetch_data)→ 实际调用的是service.fetch_data,mock 没覆盖到 - 正确写法:
@patch("service.fetch_data")或@patch("service.utils.fetch_data")(取决于 import 方式) - 最稳妥的方式:打开被测模块源码,看它是怎么 import 和使用的;或者临时加一句
print(service.fetch_data)确认实际绑定路径
如何用 patch 装饰器 mock 一个同步内部函数?
装饰器方式适合单个测试方法,清晰可控。关键点是传参顺序:被 patch 的对象会作为**第一个额外参数**注入测试函数(类似 self),位置在 self 之后、其他 fixture 之前。
@patch("myapp.service.requests.get")
def test_api_call(self, mock_get):
mock_get.return_value.status_code = 200
mock_get.return_value.json.return_value = {"ok": True}
<pre class="brush:php;toolbar:false;">result = call_external_api() # 内部调用了 requests.get
assert result == {"ok": True}
mock_get.assert_called_once_with("https://api.example.com")
- 注意:如果测试类继承自
unittest.TestCase,self是第一个参数,mock 参数排第二;如果是普通函数测试,则 mock 参数就是第一个 -
return_value设定返回值;side_effect可设异常或动态返回(如side_effect=[ValueError, {"data": 1}]) - 别漏掉
.return_value链式调用——比如 mock 返回对象的属性或方法时,必须显式设定(如mock_get.return_value.json.return_value)
用 pytest.fixture + patch.context_manager 怎么写更灵活?
当多个测试需要共用同一组 mock 行为,或想避免装饰器嵌套过深时,fixture + patch 上下文管理器组合更干净。它还能自然支持作用域(scope="function" 或 "module")。
SkillSub Pro - Python 题解与代码注释双功能技能功能概述SkillSub Pro - Python 题解与代码注释双功能技能是一项面向实际任务的技能,主要用于SkillSub Pro 是一个 Python 题解生成与代码注释的 双功能合体技能 ,专为学生、算法学习者和开发者设计;✅ 一个技能,两种用途 :;核心要点📝 题解模式 :输入题目/题号,自动生成完整 Python 题解(含详细注释、解题思路、复杂度分析);💬 注释模式 :输入 Python 代码,自动添加详细中。它将相关步骤、
@pytest.fixture
def mock_requests_get():
with patch("myapp.service.requests.get") as mock_get:
mock_get.return_value.status_code = 200
mock_get.return_value.json.return_value = {"id": 123}
yield mock_get
<p>def test_create_user(mock_requests_get):
create_user()
mock_requests_get.assert_called()</p><p>def test_update_user(mock_requests_get):
update_user()
assert mock_requests_get.call_count == 2
</p>
- 必须用
with patch(...) as ...: yield结构,否则 patch 不会在 fixture 退出时自动停止 - fixture 名和
yield的变量名可以不同,但推荐一致,避免混淆 - 如果被测函数是异步的(
async def),不能直接用patchmock 普通函数——得 mock 返回Awaitable,例如用AsyncMock(Python 3.8+)
mock 对象的 return_value 和 side_effect 容易搞混?
return_value 是静态返回,side_effect 是行为模拟:可以抛异常、返回可迭代对象、或调用真实函数。多数“不按预期返回”的问题,根源在于没分清这两者用途。
-
mock_obj.return_value = 42→ 每次调用都返回42 -
mock_obj.side_effect = ValueError→ 每次调用都抛ValueError -
mock_obj.side_effect = [1, 2, 3]→ 第一次返回1,第二次2,第三次起抛StopIteration -
mock_obj.side_effect = lambda url: {"url": url, "status": "ok"}→ 支持参数逻辑,比return_value更贴近真实行为 - 一旦设了
side_effect,return_value就被忽略——这点经常被忽略,导致 mock 表现诡异
mock 的路径、作用域、返回机制这三块叠在一起,稍不留神就失效。最省事的办法:先在被测函数里 print 出要 mock 的对象本身(比如 print(requests.get)),确认它到底来自哪、是不是你 patch 的那个对象。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










