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

为何@patch.dict生效,@patch.object却未成功打补丁requests?

问题:os.environ补丁生效但requests.get补丁失效的原因

代码场景

业务代码文件dummy.py:

# dummy.py

import os
from requests import get
def my_func():
    name = os.environ.get('name')
    response = get('http://www.google.com')
    return name, response.content

测试代码文件:

import unittest
import os
import requests
from ddt import ddt, data, unpack
from mock import patch, Mock, MagicMock
from dummy import my_func


mock_response = Mock()
mock_response.content = "...content"


@ddt
@patch.dict(os.environ, {"name": "patched"})
@patch.object(requests, requests.get.__name__, return_value=mock_response)
class TestDummy(unittest.TestCase):
    def test_dummy(self, mock_get):
        name, content = my_func()
        print("name: {}".format(name))
        print("content: {}".format(content))

用户疑问:原本认为两行装饰器行为类似,但运行测试时os.environ补丁生效,requests.get却未被补丁,原因是什么?

核心原因:导入绑定的差异

这两个补丁的本质差异在于业务代码中对目标对象的引用方式:

  • 对于os.environ:业务代码里通过os.environ.get调用,每次都会直接访问os模块中的environ字典对象,所以patch.dict修改os.environ后,后续调用能直接拿到修改后的值。
  • 对于requests.get:业务代码里用了from requests import get,这行代码会把requests模块中的get函数直接复制一份引用到dummy模块的命名空间里。后续my_func调用的get,是dummy模块里的这份本地引用,而不是requests模块里的原函数。测试补丁的是requests模块里的get,自然不会影响到dummy模块里已经绑定好的引用。

两种修复方案

方案1:修改业务代码的导入方式

把dummy.py改成导入整个requests模块,调用时通过模块访问get:

# dummy.py
import os
import requests
def my_func():
    name = os.environ.get('name')
    response = requests.get('http://www.google.com')
    return name, response.content

这样每次调用requests.get都会从requests模块获取函数,测试里的patch.object(requests, 'get', ...)就能生效。

方案2:直接补丁业务模块里的引用

如果不想修改业务代码,就直接补丁dummy模块里的get引用:

# 测试文件中的装饰器替换为
@patch.object(dummy, 'get', return_value=mock_response)

因为dummy模块里的get是my_func实际调用的对象,补丁它就能替换掉原始的get函数。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 17:03:32