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

Python中如何通过Patch测试函数外的对象实例化

解决模块导入时执行代码的Mock Patch问题

问题场景

你的bar.py在模块级别直接执行了函数调用和对象实例化:

from foo import foo # function that returns an int
from dog import Dog

dog_foo = 4 * foo()
my_dog = Dog(dog_foo)

...

这类代码会在第一次导入bar模块时立即执行,导致你之前尝试的两种patch方式都无法生效——要么patch时机不对,要么patch的位置错误。

正确的Patch方式

核心要做到两点:

  1. 在bar模块的代码执行前让patch生效;
  2. 针对bar模块内的foo引用进行patch(而非原foo模块的foo);
  3. 若模块已被缓存,需重新加载模块触发代码重新执行。

情况1:首次导入bar(无模块缓存)

直接在patch上下文内导入bar,确保模块级代码执行时mock已生效:

from unittest.mock import patch

with patch("bar.foo") as mock_foo:
    # 设置mock返回值
    mock_foo.return_value = 5
    # 首次导入bar,此时模块级代码会使用mock后的foo
    import bar
    
    # 验证结果
    assert bar.dog_foo == 20  # 4 * 5 = 20
    # 假设Dog类将传入参数保存到了self.value属性,验证实例化正确性
    assert bar.my_dog.value == 20

情况2:bar已被导入(存在模块缓存)

如果测试代码或其他用例已经导入过bar,需要用importlib.reload()重新加载模块,让模块级代码重新执行:

from unittest.mock import patch
import importlib
import bar  # 之前已导入过bar,模块被缓存

with patch("bar.foo") as mock_foo:
    mock_foo.return_value = 5
    # 重新加载bar模块,触发模块级代码再次执行
    bar = importlib.reload(bar)
    
    # 验证结果
    assert bar.dog_foo == 20
    assert bar.my_dog.value == 20

为什么之前的方式无效?

  • patch foo.foo无效:当bar中使用from foo import foo时,会把foo.foo的引用复制到bar模块的命名空间中成为bar.foo。后续patch原foo.foo不会改变bar内已存在的引用,所以模块级代码还是会调用原函数。
  • patch时机错误:如果在patch生效前已经导入过bar,模块缓存会直接返回已执行过代码的模块对象,后续的patch无法影响已经实例化的my_dog。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 05:21:13