如何向PropertyMock传递self参数?Mock属性遇参数缺失报错
问题描述
Mock普通类方法时,设置autospec=True可以自动传递self参数:
def do_thing_side_effect(self): pass mocker.patch('module.class.do_thing', side_effect=do_thing_side_effect, autospec=True)
但Mock类属性的getter方法时,无论设置autospec=True还是spec=True,self参数都无法被传递,触发TypeError:
def thing_side_effect(self): pass mocker.patch('module.class.thing', new=mocker.PropertyMock(side_effect=thing_side_effect, autospec=True))
报错信息:
Traceback (most recent call last): File "/usr/local/lib/python3.9/unittest/mock.py", line 2848, in __get__ return self() File "/usr/local/lib/python3.9/unittest/mock.py", line 1092, in __call__ return self._mock_call(*args, **kwargs) File "/usr/local/lib/python3.9/unittest/mock.py", line 1096, in _mock_call return self._execute_mock_call(*args, **kwargs) File "/usr/local/lib/python3.9/unittest/mock.py", line 1157, in _execute_mock_call result = effect(*args, **kwargs) TypeError: thing_side_effect() missing 1 required positional argument: 'self'
尝试替换为spec参数、使用new_callable搭配spec,都会触发相同错误。
解决方案
方法1:用Lambda包装副作用函数
通过lambda捕获属性访问时的实例参数,再手动传递给你的副作用函数:
def thing_side_effect(self): return f"mocked value for {self}" mocker.patch( 'module.class.thing', new=mocker.PropertyMock(side_effect=lambda self: thing_side_effect(self)) )
方法2:让副作用函数兼容无参调用
直接修改副作用函数,使其接受任意参数并提取实例:
def thing_side_effect(*args): self = args[0] if args else None # 这里编写依赖self的逻辑,比如访问self的其他属性 return "mocked property value" mocker.patch('module.class.thing', new=mocker.PropertyMock(side_effect=thing_side_effect))
方法3:自定义PropertyMock子类
重写PropertyMock的__get__方法,强制将实例传递给副作用函数:
from unittest.mock import PropertyMock class SelfAwarePropertyMock(PropertyMock): def __get__(self, instance, owner): if self.side_effect: return self.side_effect(instance) return super().__get__(instance, owner) def thing_side_effect(self): return self.some_other_attribute mocker.patch('module.class.thing', new=SelfAwarePropertyMock(side_effect=thing_side_effect))
关键原因
普通方法Mock时,autospec=True会模拟方法的绑定行为,自动把实例作为第一个参数传给副作用函数。但PropertyMock本质是模拟描述符,它的默认__get__方法调用副作用函数时不会自动传递实例参数,因此需要手动处理实例的传递逻辑。
内容的提问来源于stack exchange,提问作者William Edwards
相关产品推荐
相关产品推荐

