某些类在类级别(__init__
之外或任何其他函数)定义其属性(也称为字段)。有些类在__init__
函数内或甚至从其他函数中定义它们。有些课程使用这两种方法。
class MyClass(object):
foo = 'foo'
def __init__(self, *args, **kwargs):
self.bar = 'bar'
问题是,当您使用dir
时,如果您传入了该类的实例,则它只包含'bar'
。
>>> dir(MyClass)
['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'foo']
>>> myInstance = MyClass()
>>> dir(myInstance)
['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'bar', 'foo']
(滚动到最右边看差异)
我遇到的情况是我需要避免实例化MyClass
,但我想将其用作spec
设置(通过isinstance
检查)mock.patch
打电话给单元测试。
@mock.patch('mypackage.MyClass', spec=MyClass)
def test_thing_that_depends_on_MyClass(self, executeQueryMock):
# uses 'thing' here, which uses MyClass.bar ...
这样做会导致:
AttributeError:Mock对象没有属性'bar'
这是有道理的,因为mock docs说:
spec:这可以是字符串列表,也可以是充当模拟对象规范的现有对象(类或实例)。 如果传入一个对象,则通过在对象上调用dir(不包括不受支持的魔术属性和方法)来形成字符串列表。访问不在此列表中的任何属性将引发AttributeError。
即使我实例化MyClass
,我也会遇到不同的错误。
@mock.patch('mypackage.MyClass', spec=MyClass())
def test_thing_that_depends_on_MyClass(self, executeQueryMock):
# uses 'thing' here, which uses MyClass.bar ...
原因:
TypeError:'NonCallableMagicMock'对象不可调用
我真的不关心我允许访问哪些功能/属性;我实际上想要正常的MagicMock行为,它可以让你在没有AttributeError
的情况下调用任何东西。即使我只是使用spec
传递spec
支票,似乎使用isinstance
也会严格限制。
如何正确模拟isinstance
检查中使用的类,并且具有未在类级别定义的属性?
答案 0 :(得分:1)
鉴于您只想传递isinstance
个检查,我认为最简单的解决方案是为mock.patch.object
编写一个快速包装器,设置返回模拟的__class__
属性。
def my_patch(obj, attr_name):
fake_class = mock.MagicMock()
fake_instance = fake_class.return_value # calling a class returns an instance.
fake_instance.__class__ = getattr(obj, attr_name)
return mock.patch.object(obj, attr_name, fake_class)
它像mock.patch.object
一样使用:
@my_patch(some_module, 'MyClass')
def test_something(self, fake_my_class):
...
但假对象应该通过isinstance
检查,就像spec'd mock一样。