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

如何用MagicMock的spec和wraps测试Pydantic BaseModel

解决Pydantic BaseModel的Mock问题(兼顾spec安全与wraps便捷性)

问题原因

当使用MagicMock(wraps=MyClass(), spec=MyClass)Mock Pydantic v2的BaseModel子类时,访问实例属性会抛出AttributeError: Mock object has no attribute 'a'。这是因为Pydantic通过元类机制动态生成实例属性,类的dir()或__dict__中不会提前包含字段属性,而MagicMock的spec依赖对象的dir()来识别合法属性,导致无法正确识别Pydantic字段。

解决方案

方案1:用实例生成spec(推荐)

直接使用Pydantic实例作为spec的参数,因为实例化后Pydantic会把字段转为实例属性,dir(instance)能正确包含所有字段。这样既保留了spec的安全性,又能通过wraps自动转发未Mock的调用。

修改后的fixture代码:

@pytest.fixture(name='myclass')
def fixture_myclass():
    real_instance = MyClass()
    yield MagicMock(wraps=real_instance, spec=real_instance)

测试验证:

def test_myclass_wraps(myclass):
    # 直接访问属性,会转发给真实实例
    assert myclass.a == '123'
    # Mock方法后生效
    myclass.some_method.return_value = "mock"
    assert myclass.some_method() == "mock"
    # 访问不存在的属性会触发AttributeError,保障测试安全
    with pytest.raises(AttributeError):
        _ = myclass.non_exist_attr

方案2:手动合并类与实例的属性列表

如果需要同时Mock类级别的方法和实例字段,可以手动合并类的方法列表与Pydantic字段名,作为spec的属性集合:

@pytest.fixture(name='myclass')
def fixture_myclass():
    real_instance = MyClass()
    # 合并类的方法和Pydantic字段
    valid_attrs = dir(MyClass) + list(MyClass.model_fields.keys())
    yield MagicMock(wraps=real_instance, spec=valid_attrs)

这种方式适合需要覆盖类方法(如MyClass.some_class_method)的场景,同时保证实例字段能被正确识别。

原理说明

  • spec=instance:利用Pydantic实例化后生成的真实属性列表,让MagicMock能识别所有合法的实例字段和方法。
  • wraps=real_instance:将未被Mock的属性访问、方法调用转发给真实实例,无需手动Mock每个属性/方法,减少工作量。
  • spec的安全性:访问不在实例属性列表中的字段时,会抛出AttributeError,避免测试中出现拼写错误或访问不存在的属性。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 01:14:59