发布于2026-05-21 阅读(0)
扫一扫,手机访问

在 Python 单元测试中,用 mockito 模拟某个方法失败,往往不是因为语法错误,而是因未在被测模块的命名空间中打补丁——必须 mock 被测类实际引用的函数路径(即 from models.crud import get_plane_by_id 后在类中直接调用的 get_plane_by_id),而非原始定义位置。
你有没有遇到过这种情况?在 Python 单元测试里,明明用 mockito 把某个函数给“替换”掉了,可一运行测试,它还是固执地调用了原始实现。语法检查没问题,但模拟就是不起作用。
问题往往不在于代码写错了,而在于“打补丁”的位置没找对。核心在于,你必须模拟被测模块实际使用的那个函数引用,而不是函数最初定义的那个地方。
这背后的关键,是 Python 的导入机制。举个例子,假设你的被测类 PersistAircraftEvents 定义在 services/aircraft.py 文件里,并且文件开头有这样一行导入语句:
from models.crud import get_plane_by_id, create_plane
当这行代码执行时,get_plane_by_id 这个函数对象就从 models.crud 模块被绑定到了当前模块 services.aircraft 的局部命名空间。此后,在 PersistAircraftEvents 类内部,你调用的 get_plane_by_id(...),实际上指向的是 services.aircraft.get_plane_by_id 这个引用,而不再是 models.crud.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"
)
# ✅ 模拟在 services.aircraft 模块中导入的那个函数
when(services.aircraft).get_plane_by_id(...).thenReturn(None)
try:
service.persist_aircraft_event(event)
# 这里添加你的断言逻辑...
finally:
unstub() # 清理 mock,避免污染其他测试
看到了吗?关键在于 import services.aircraft 这一行,然后我们针对 services.aircraft.get_plane_by_id 进行模拟。这才是函数在被测类眼中真正的“模样”。
为了让这个知识点更清晰,我们不妨梳理几个典型的错误和对应的正确做法:
when(models.crud).get_plane_by_id(...)。这修改的是源模块,但调用发生在另一个命名空间里,所以模拟无效。from models.crud import get_plane_by_id,再 import models.crud 并尝试模拟后者。这依然无效,因为第一次导入已经创建了一个独立的引用。services.aircraft),并对其内部的函数引用进行打补丁。unstub()(建议放在 finally 块中)来清理模拟,这在像 pytest 这样测试用例共享进程上下文的框架中尤为重要。monkeypatch 夹具达到类似效果。但无论使用哪种工具,记住“在调用发生的地方进行模拟”这个核心原则总是最可靠的。说到底,Mock 的本质是劫持运行时调用链上的具体目标。在 Python 中,from X import Y 这种语法会创建一个指向 Y 的新引用。因此,你的模拟操作必须发生在这个新引用被创建和使用的地方——也就是导入它的那个模块内部。
找准这个“落地点”,你的模拟就能精准命中目标。下次再遇到模拟失效的问题,不妨先问自己一句:“我模拟的,真的是它正在调用的那个东西吗?”
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
正版软件
正版软件
正版软件
正版软件
正版软件
1
2
3
7
8