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

使用unittest.mock上下文管理器时,如何正确调用assert_called_once?

问题根源与解决办法

核心问题:Mock的目标路径错误

你遇到的AttributeError本质是你以为替换成Mock对象的函数,实际上还是原函数——原生Python函数本身没有assert_called_once()方法,自然会报错。

最常见的原因是:你mock的是get_score_json的定义模块,而非被测试函数calc_scores实际调用它的模块。

举个实际场景例子:
假设你的项目结构如下:

my_project/
├── score_utils.py  # 定义get_score_json的文件
└── calculator.py   # 包含calc_scores的文件,里面用from score_utils import get_score_json导入并调用

当calculator.py执行from score_utils import get_score_json时,会把get_score_json的引用复制到calculator模块的命名空间里。如果你测试时mock的是score_utils.get_score_json,根本不会影响calculator模块里已经存在的那个函数引用——calc_scores还是在调用原函数,不是Mock对象。


正确写法示例

被测试代码(calculator.py)

from score_utils import get_score_json

def calc_scores():
    score_data = get_score_json()
    return sum(score_data.values())

测试代码(test_calculator.py)

from unittest.mock import patch
from calculator import calc_scores

def test_calc_scores():
    # 关键:mock的是calculator模块里的get_score_json,而非score_utils里的原函数
    with patch('calculator.get_score_json') as mock_get_score:
        # 设置Mock的返回值
        mock_get_score.return_value = {'math': 92, 'chinese': 88}
        # 执行被测试函数
        total = calc_scores()
        # 现在mock_get_score是标准Mock对象,支持assert_called_once()
        mock_get_score.assert_called_once()
        # 验证计算结果
        assert total == 180

其他可能的坑

  1. 不要用new参数替换普通函数:如果你给patch传了new=lambda: {}这类普通函数,替换后的对象是普通函数,不是Mock对象,自然没有断言方法。
  2. 不要在上下文管理器外调用断言:patch的上下文结束后,Mock对象会被还原成原函数,这时调用assert_called_once()同样会触发错误。

内容的提问来源于stack exchange,提问作者ssloan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 10:20:43