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

如何以上下文管理器方式使用patch()并获取自定义Mock实例

上下文返回的mock对象本质

当向patch()传入自定义类作为替换目标时,as关键字绑定的对象就是传入的DatabaseMock类本身,而非类的实例。
patch的执行逻辑仅为将指定导入路径下的原对象替换为传入的新对象,不会主动触发类的实例化。类的实例化动作只会在被测试代码实际调用该数据库类时发生。你在__init__方法中定义的x是实例属性,仅在类实例化后才会绑定到实例对象上,直接访问类本身的x属性自然会抛出AttributeError。
将x改为类属性后可以访问,本质是因为类对象本身持有了该属性,但类属性会被所有类实例共享,不同测试用例运行时如果没有手动重置,状态会持续保留,必然违反测试隔离要求,该方案不可用。

正确获取实例的实现方式

以下三种方案均可以满足测试隔离要求,根据业务场景选择即可:

  • 方案1:通过return_value获取单实例
    只要被测试代码中仅对数据库类做一次实例化,生成的实例会自动挂载到类的return_value属性上(patch会自动为传入的替换类添加mock跟踪属性),直接访问即可:
    from unittest.mock import patch
    class TestFunctions():
        def test_function(self):
            with patch("path.to.database.call", DatabaseMock) as mock_db_cls:
                result = function_i_am_testing()
                # 获取被测试代码运行时生成的DatabaseMock实例
                mock_db_instance = mock_db_cls.return_value
                assert mock_db_instance.x == result
    
    如果被测试代码中存在多次实例化逻辑,可通过mock_db_cls.return_value_list按实例化顺序获取所有生成的实例。
  • 方案2:自定义实例跟踪逻辑,适配多实例场景
    如果测试逻辑涉及多次数据库类初始化,可在自定义mock类中添加轻量的实例跟踪能力,同时配套重置方法保证测试隔离:
    class DatabaseMock():
        _instances = []
        def __init__(self, host=None):
            self.host = host
            self.x = {}
            # 初始化时将当前实例存入跟踪列表
            self.__class__._instances.append(self)
       
        @classmethod
        def reset(cls):
            # 清空实例记录,避免跨用例状态污染
            cls._instances.clear()
    
    # 测试代码
    class TestFunctions():
        def setup_method(self):
            # 每个测试用例执行前先重置mock状态
            DatabaseMock.reset()
            
        def test_function(self):
            with patch("path.to.database.call", DatabaseMock):
                result = function_i_am_testing()
                # 按实例化顺序获取对应实例即可
                assert DatabaseMock._instances[0].x == result
    
  • 方案3:继承MagicMock实现,保留原生mock能力
    自定义__init__方法不影响类继承MagicMock,只要在构造方法中调用父类初始化逻辑,即可同时保留自定义属性和原生mock的所有能力,无需额外编写跟踪逻辑:
    from unittest.mock import MagicMock
    class DatabaseMock(MagicMock):
        def __init__(self, host=None, *args, **kwargs):
            super().__init__(*args, **kwargs)
            self.host = host
            self.x = {}
    
    该写法完全兼容return_value、调用断言等原生mock特性,适配绝大多数测试场景。

注意:类级别属性仅可用于存储实例跟踪列表、重置方法这类测试辅助逻辑,禁止存储业务状态数据,每个用例执行前必须执行重置操作,从根源上避免跨用例状态污染。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.03 10:03:43