如何基于不可调用的spec创建可调用的mock对象?
解决方案
问题根源
- 用
One实例作为autospec参数时,mock会将One视为不可调用的实例对象,而非可生成实例的类,因此抛出NonCallableMagicMock不可调用的错误。 - 仅用
autospec=True时,默认生成的mock实例允许手动添加或访问原类不存在的属性,无法检测到One属性变更但Wrapper未同步的问题。
正确实现方式
要同时满足「mock类可调用生成实例」和「严格校验实例属性的存在性」,可通过以下两种方法实现:
方法一:使用create_autospec创建严格mock
create_autospec可以基于原类生成严格遵循其结构的mock,结合spec_set=True禁止添加原类不存在的属性:
from unittest import mock import pytest class One: def __init__(self, a): self.a = a class Wrapper: def __init__(self, wa): self._one = One(a=wa) self.wa = self._one.a def test_wrapper(): # 创建严格遵循One类结构的mock,spec_set=True限制属性必须存在于原类 MockOne = mock.create_autospec(One, spec_set=True) test_a = 'bar' # 设置mock实例的a属性(仅当原类存在a时可操作) MockOne.return_value.a = test_a # 替换原One类 with mock.patch(__name__ + '.One', MockOne): wrapper_obj = Wrapper(wa=test_a) MockOne.assert_called_once_with(a=test_a) assert wrapper_obj.wa == test_a
方法二:结合autospec=True与spec_set限制实例属性
在patch时启用autospec=True,同时为mock的返回实例设置spec_set,严格校验实例属性:
from unittest import mock import pytest class One: def __init__(self, a): self.a = a class Wrapper: def __init__(self, wa): self._one = One(a=wa) self.wa = self._one.a @mock.patch(__name__ + '.One', autospec=True) def test_wrapper(MockOne): test_a = 'bar' # 创建严格遵循One实例结构的mock对象,禁止添加不存在的属性 mock_instance = mock.Mock(spec_set=One(a=test_a)) mock_instance.a = test_a MockOne.return_value = mock_instance wrapper_obj = Wrapper(wa=test_a) MockOne.assert_called_once_with(a=test_a) assert wrapper_obj.wa == test_a
验证属性变更检测
当One的属性被修改(比如将self.a改为self.b),而Wrapper仍保留self.wa = self._one.a时,测试会抛出AttributeError: Mock object has no attribute 'a',从而检测到Wrapper未同步更新的问题,符合需求。
内容的提问来源于stack exchange,提问作者vlc146543
相关产品推荐
相关产品推荐

