[英]Mock modules and subclasses (TypeError: Error when calling the metaclass bases)
要編譯readthedocs上的文檔,必須模擬模塊h5py。 我收到一個錯誤,可以使用這個簡單的代碼重現:
from __future__ import print_function
import sys
try:
from unittest.mock import MagicMock
except ImportError:
# Python 2
from mock import Mock as MagicMock
class Mock(MagicMock):
@classmethod
def __getattr__(cls, name):
return Mock()
sys.modules.update({'h5py': Mock()})
import h5py
print(h5py.File, type(h5py.File))
class A(h5py.File):
pass
print(A, type(A))
class B(A):
pass
該腳本的輸出是:
<Mock id='140342061004112'> <class 'mock.mock.Mock'>
<Mock spec='str' id='140342061005584'> <class 'mock.mock.Mock'>
Traceback (most recent call last):
File "problem_mock.py", line 32, in <module>
class B(A):
TypeError: Error when calling the metaclass bases
str() takes at most 1 argument (3 given)
模擬h5py
和h5py.File
的正確方法是什么?
在我看來,這個問題對於使用readthedocs的文檔非常普遍,其中一些模塊必須被模擬。 社區有一個答案是有用的。
你不能真正使用Mock
實例作為類 ; 它在Python 2上很難實現,並且只是偶然地在Python 3中工作(見下文)。
如果您希望它們在類層次結構中工作,則必須返回Mock
類本身:
>>> class A(Mock): # note, not called!
... pass
...
>>> class B(A):
... pass
...
>>> B
<class '__main__.B'>
>>> B()
<B id='4394742480'>
如果您無法導入h5py 可言 ,這意味着你需要保持在您返回類而不是一個實例類手動更新列表:
_classnames = {
'File',
# ...
}
class Mock(MagicMock):
@classmethod
def __getattr__(cls, name):
return Mock if name in _classnames else Mock()
這不是萬無一失的; 沒有辦法在classmethod中檢測父實例,所以h5py.File().File
會導致返回另一個'class',即使在實際的實現中是其他對象。 您可以通過創建一個新的描述符來代替classmethod
裝飾器來部分解決這個問題,該類classmethod
裝飾器將綁定到類或實例(如果有的話); 這樣你至少會在你的Mock
類的實例上有self._mock_name
形式的上下文。
在Python 3中,當用作基類時, 直接使用MagicMock
而無需進一步定制:
>>> from unittest.mock import MagicMock
>>> h5py = MagicMock()
>>> class A(h5py.File): pass
...
>>> class B(A): pass
...
但這不是真正有意和支持的行為; 從類名字符串中“引用”類和子類:
>>> A
<MagicMock spec='str' id='4353980960'>
>>> B
<MagicMock spec='str' id='4354132344'>
由於實例不起作用,因此有各種各樣的問題:
>>> A()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/Users/mjpieters/Development/Library/buildout.python/parts/opt/lib/python3.5/unittest/mock.py", line 917, in __call__
return _mock_self._mock_call(*args, **kwargs)
File "/Users/mjpieters/Development/Library/buildout.python/parts/opt/lib/python3.5/unittest/mock.py", line 976, in _mock_call
result = next(effect)
StopIteration
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.