
在 Python 单元测试中,用 mockito 模拟某个方法失败,往往不是因为语法错误,而是因未在被测模块的命名空间中打补丁——必须 mock 被测类实际引用的函数路径(即 from models.crud import get_plane_by_id 后在类中直接调用的 get_plane_by_id),而非原始定义位置。
在 python 单元测试中,用 mockito 模拟某个方法失败,往往不是因为语法错误,而是因未在**被测模块的命名空间中打补丁**——必须 mock 被测类实际引用的函数路径(即 `from models.crud import get_plane_by_id` 后在类中直接调用的 `get_plane_by_id`),而非原始定义位置。
问题核心在于 Python 的导入机制:当你在 PersistAircraftEvents 所在模块(例如 services/aircraft.py)中执行 from models.crud import get_plane_by_id 时,该函数已被绑定到当前模块的局部命名空间。因此,mockito.when() 必须作用于被测模块(mut)中实际使用的 get_plane_by_id 引用,而非 models.crud.get_plane_by_id。
✅ 正确做法:在被测类所在的模块中 mock 导入的函数名
假设 PersistAircraftEvents 定义在 services/aircraft.py 中,且该文件开头有:
from models.crud import get_plane_by_id, create_plane
那么你的测试应 mock services.aircraft.get_plane_by_id(即函数在被测模块中的“落地点”),而非 models.crud.get_plane_by_id:
from mockito import when, unstub
from services.aircraft import PersistAircraftEvents # ✅ 导入被测类
import services.aircraft # ✅ 导入其所在模块(关键!)
class TestPersistAircraftEvents:
def test_unknown_aircraft_type(self):
db = mock()
service = PersistAircraftEvents(db)
event = ReceivedAircraftEvent(
event_time=datetime.now(),
aircraft_id="what?",
event_type="test"
)
# ✅ Mock the function *as imported in services.aircraft*
when(services.aircraft).get_plane_by_id(...).thenReturn(None)
try:
service.persist_aircraft_event(event)
# 断言逻辑...
finally:
unstub() # 清理 mock,避免污染其他测试⚠️ 常见误区与注意事项:
仅使用 Python 将 Claw Code 虚拟化框架与 OpenClaw 集成,提供 184 种工具和 200 多条命令,用于安全分析和代码质量...
- ❌ when(models.crud).get_plane_by_id(...) 失败:它修改的是 models.crud 模块内的函数,但 PersistAircraftEvents 调用的是自己命名空间里的副本;
- ❌ from models.crud import get_plane_by_id 后再 import models.crud 并 mock —— 仍无效,因导入已创建独立引用;
- ✅ 务必 import services.aircraft(或你实际存放 PersistAircraftEvents 的模块),并对其 .get_plane_by_id 打补丁;
- ✅ 使用 unstub()(推荐在 finally 块中)确保 mock 隔离,尤其在 pytest 中多个测试共用同一进程时;
- ? 若使用 pytest,也可结合 monkeypatch 实现类似效果,但 mockito 风格下坚持“patch 使用处”原则最可靠。
总结:Mock 的本质是劫持运行时调用链上的目标对象。Python 中 from X import Y 创建的是对 Y 的新引用,因此 mock 必须发生在该引用被创建的位置——也就是被测模块自身。找准这个模块,就找准了 mock 的正确靶心。
立即学习“Python免费学习笔记(深入)”;

















