如何使用pytest-mock在单元测试中验证函数是否被调用?
用pytest + pytest-mock验证函数调用的正确姿势
我来帮你搞定这个问题!你遇到的报错本质是patch的目标路径不正确,这是pytest-mock新手非常容易踩的坑。下面一步步给你讲清楚正确的实现方式:
核心问题分析
在你的代码里,my_function调用的是当前模块内的hello函数,但直接写mocker.patch('hello')会让pytest找不到正确的目标对象——因为patch需要明确指定被替换函数的完整路径(不管是当前模块还是其他模块)。
修正后的同模块测试代码
如果测试代码和被测试函数在同一个文件(比如test_hello.py),可以这样写:
def hello(name): return f'Hello {name}' def my_function(): hello('Sam') def test_hello(mocker): # 用__name__获取当前模块名,拼接成完整路径,避免硬编码 mocked_hello = mocker.patch(f"{__name__}.hello") # 执行被测试函数 my_function() # 验证hello是否以指定参数被调用了一次 mocked_hello.assert_called_once_with('Sam')
关键步骤拆解
- 自动获取mocker fixture:不需要额外导入任何库,只要在测试函数参数里声明
mocker,pytest会自动注入这个fixture。 - 正确指定patch路径:
- 同模块场景:用
f"{__name__}.函数名"是最稳妥的写法,不管文件重命名还是模块结构变化都不会出错。 - 跨模块场景:假设
hello和my_function在my_module.py里,测试文件在tests/test_my_module.py,那就要patch'my_module.hello'——注意,这里的路径是被调用处的模块路径,不是函数定义的路径(这点一定要记牢!)。
- 同模块场景:用
- 常用调用验证断言:
assert_called_once_with('Sam'):验证函数被恰好调用一次,且参数完全匹配。assert_called_with('Sam'):验证函数最后一次调用的参数匹配(不管调用多少次)。assert_called():验证函数至少被调用过一次。assert_not_called():验证函数从未被调用。
跨模块测试示例(更贴近真实项目)
如果你的项目结构是这样:
my_project/ ├── my_module.py └── tests/ └── test_my_module.py
my_module.py内容:
def hello(name): return f'Hello {name}' def my_function(): hello('Sam')
tests/test_my_module.py内容:
from my_module import my_function def test_my_function_calls_hello(mocker): # patch目标是my_module里的hello,也就是my_function实际调用的那个 mocked_hello = mocker.patch('my_module.hello') my_function() # 验证调用情况 mocked_hello.assert_called_once_with('Sam')
运行测试
在终端执行命令:
pytest test_hello.py -v
就能看到测试通过的结果啦~
内容的提问来源于stack exchange,提问作者Evgenii
相关产品推荐
相关产品推荐

