简体   繁体   English

无法在python中模拟__subclasses__

[英]Unable to mock __subclasses__ in python

Why does the following code not work? 为什么以下代码不起作用?

>>> from mock import *
>>> class A(object):
...     pass
...
>>> mock = create_autospec(A)
>>> mock.foo = Mock()                # this works
>>> mock.__bar__ = Mock()            # this works too
>>> mock.__subclasses__ = Mock()     # this fails
AttributeError: Mock object has no attribute '__subclasses__'

I think I'm following the documentation on mocking magic methods here. 我正在关注模拟魔术方法的文档。 The docs do remark that trying to mock a magic method which is not in the spec will not work. 该文档确实指出,尝试模拟规范中未包含的魔术方法将不起作用。 But why would __subclasses__ not be in the spec of an autospecced new-style class? 但是为什么__subclasses__ 不在自动指定的新样式类的规范中?

__subclasses__ is not part of the class spec. __subclasses__ 不是类规范的一部分。 It is part of the metatype of the class ( type here). 它是类的元类型的一部分( type这里)。

Python always looks up special methods on the type , never directly. Python总是在类型上查找特殊的方法 ,而不是直接查找 If and when Python needs to call __subclasses__ , it'll not do so directly, it'll use type(classobj).__subclasses__(classobj) to look up the unbound method and pass in the first argument manually. 如果并且当Python需要调用__subclasses__ ,它不会直接调用__subclasses__ ,它将使用type(classobj).__subclasses__(classobj)查找未绑​​定的方法并手动传递第一个参数。 As such, adding __subclasses__ to the mock of a class is not going to be enough. 因此, __subclasses__在类的模拟中添加__subclasses__是不够的。

The same applies to special methods intended to operate on instances; 这同样适用于旨在对实例进行操作的特殊方法。 Mock will happily take __add__ or __str__ along when using create_autospec() , and that works then for instances of the mocked class where Python will use type(mockinstance).__str__(mockinstance) to invoke the __str__ method. 当使用create_autospec()Mock会很高兴地使用__add____str__ ,并且适用于Mock类的实例 ,其中Python将使用type(mockinstance).__str__(mockinstance)来调用__str__方法。

If your own code calls classobj.__subclasses__() directly, you'll need to pass in a class mock that explicitly sets that method; 如果您自己的代码直接调用classobj.__subclasses__() ,则需要传入一个明确设置该方法的类模拟; you can't expect it to be auto-specced here. 您不能期望它会在此处自动指定。

Mocks don't like you setting any valid magic method: 嘲弄者不喜欢您设置任何有效的魔术方法:

>>> m = create_autospec(A)
>>> m.__add__ = Mock()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Users/mj/Development/venvs/stackoverflow-2.7/lib/python2.7/site-packages/mock.py", line 767, in __setattr__
    raise AttributeError("Mock object has no attribute '%s'" % name)
AttributeError: Mock object has no attribute '__add__'

only non-default magic methods are allowed: 仅允许使用非默认的魔术方法:

>>> m.__dummy__ = Mock()
>>> m.__dummy__
<Mock name='mock.__dummy__' id='4427608656'>

You can create a subclass of A adding in the __subclass__ method to allow you to mock it: 您可以在__subclass__方法中添加A的子类,以模拟它:

>>> class AMockSpec(A):
...     def __subclasses__(self): pass
...
>>> m = create_autospec(AMockSpec)
>>> m.__subclasses__ = Mock()
>>> m.__subclasses__.return_value = ['SomeMockValue']
>>> m.__subclasses__()
['SomeMockValue']

The following does work ( __subclasses__ is available on __class__ ): 以下工作正常( __class__上提供__subclasses__ ):

>>> from mock import *
>>> class A(object):
...     pass
...
>>> m = create_autospec(A)
>>> m.__class__.__subclasses__()
[]
>>> class B(A): pass
...
>>> m.__class__.__subclasses__()
[<class '__main__.B'>]
>>> m.__class__.__subclasses__ = Mock()
>>> m.__class__.__subclasses__()
<Mock name='mock()' id='4372594896'>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM