Python unittest如何Mock对象使属性访问抛出AttributeError
解决方案
首先明确两个核心问题原因:
- 普通
Mock对象的side_effect仅在调用mock对象(即执行mock_obj())时触发,属性访问是直接取值操作,不会触发调用逻辑,因此你之前的写法无法生效。 @property装饰的属性是类层面的描述符,直接在实例上执行del instance.foo无法删除类层面的描述符定义,因此会触发报错。
推荐方案:使用PropertyMock拦截属性访问
unittest.mock提供了专门用于mock属性的PropertyMock工具,结合patch.object替换目标类的对应属性,为其设置side_effect=AttributeError即可完全模拟属性不存在的行为,示例代码如下:
from unittest.mock import patch, PropertyMock # 示例业务类 class DemoClass: @property def foo(self): return "正常属性返回值" instance = DemoClass() # 测试上下文内打补丁 with patch.object(DemoClass, "foo", new_callable=PropertyMock) as mock_foo: mock_foo.side_effect = AttributeError("属性不存在") # 行为和真实缺失属性完全一致 print(hasattr(instance, "foo")) # 输出False instance.foo # 触发AttributeError: 属性不存在
该方案的补丁仅在
with代码块内生效,不会修改全局类定义,不会干扰其他测试用例,是单元测试场景下的最优选择。
可选方案:自定义描述符替换(无mock库依赖)
如果不想使用mock库工具,可以自定义一个抛出异常的描述符临时替换类上的原property,测试完成后手动还原即可:
class MissingAttrDescriptor: def __get__(self, instance, owner): raise AttributeError("属性不存在") # 暂存原属性定义 original_foo = DemoClass.foo # 替换为抛错描述符 DemoClass.foo = MissingAttrDescriptor() try: print(hasattr(instance, "foo")) # 输出False instance.foo # 触发AttributeError finally: # 还原原属性,避免污染其他逻辑 DemoClass.foo = original_foo
避坑说明
- 不要直接给实例赋值
instance.foo = Mock(side_effect=AttributeError()):该写法下访问instance.foo只会拿到Mock对象本身,只有执行instance.foo()调用时才会抛错,和真实属性访问行为不符。 - 不要尝试在实例层面删除property:property定义在类层面,实例本身无对应属性存储条目,
del操作会直接报错。
内容的提问来源于stack exchange,提问作者run_the_race
相关产品推荐
相关产品推荐

