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

Python unittest中PropertyMock的side_effect仅单次调用问题

问题根因

test_prop输出两次text_0的核心原因是patch参数写法错误:

  • new_callable参数要求传入可调用的类/工厂函数,由patch在进入上下文管理器时自动调用它,生成用来替换目标属性的mock实例。
  • 你当前写法是提前实例化好PropertyMock(side_effect=side_effect_func)对象直接传给new_callable。patch检测到传入的不是可调用的工厂,而是已经生成的实例对象时,会直接把该实例作为静态替换值,不会正确触发PropertyMock作为描述符的每次访问拦截逻辑:第一次属性访问拿到side_effect返回值后,后续访问会直接复用第一次的结果,不会重复执行side_effect函数。

test_func能正常输出text_0, text_1,是因为你直接把side_effect参数传给了patch,由patch正确给替换方法的Mock实例配置side_effect,每次调用方法都会正常触发计数累加。

正确实现方式

要让property每次被访问都触发side_effect,按以下两点修正即可:

  1. 给new_callable传入PropertyMock类本身,不要提前实例化;将side_effect作为patch.object/patch的独立关键字参数传入,patch会自动把这些参数透传给PropertyMock的构造函数,生成正确配置的mock实例。
  2. side_effect函数需要预留一个形参,接收触发属性访问的类实例——PropertyMock执行side_effect时,会自动把当前访问属性的实例作为第一个参数传入。

修正后的test_prop代码如下:

def test_prop(self):
    side_effect_counter = -1
    # 增加形参接收PropertyMock自动传入的实例对象
    def side_effect_func(instance):
        nonlocal side_effect_counter
        side_effect_counter += 1
        return f'text_{side_effect_counter}'

    c2_1 = dut.Class2('class2',  dut.Class1('class1'))
    c2_2 = dut.Class2('class2_2', dut.Class1('class1_2'))
    # new_callable传PropertyMock类,side_effect作为独立参数传入
    with patch.object(dut.Class1, 'name', new_callable=PropertyMock, side_effect=side_effect_func):
        print(f'{c2_2.class1.name}, {c2_1.class1.name}')

执行后输出和test_func一致,为text_0, text_1,每次访问property都会正常触发side_effect函数,计数按访问次数累加。

补充说明:如果需要根据不同实例返回不同值,直接在side_effect_func里判断传入的instance参数即可,不需要依赖全局计数器,更贴合模拟不同Class1实例属性的场景需求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 03:27:22