You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 03:22:42