[英]python mock: replacing a class method
考慮以下代碼(這不是一個很好的設計,但這就是重點):
class A(object):
def __init__(self,filepath):
self._access_file_system(filepath)
def get(self):
return self._result_dict
class B(object):
def __init__(self,filepath1,filepath2):
self._filepath1 = filepath1
self._filepath2 = filepath2
def foo(self):
a1 = A(self._filepath1).get()
a2 = A(self._filepath2).get()
return a1['result']==a2['result']
現在,如果我想測試B.foo()
,我需要模擬A
(因為它訪問了構造函數中的文件系統)。
要編寫一個測試,將確保B.foo()
返回False
的情況下, a1.get()
和a2.get()
提供不同的價值觀,我還需要模擬B.get()
因此,測試功能可能應如下所示:
import mock
mock_get = mock.MagicMock(side_effect=[{'result': 0}, {'result': 1}])
@mock.patch('__main__.A')
def test_foo(MockA):
b = B('/file1','/file2')
res = b.foo()
assert res
MockA.assert_any_call('/file1')
MockA.assert_any_call('/file2')
#Doesn't work -
#the assignment doesn't propagate into the objects instantiated inside foo()
#A.get = mock_get
#The assigned method propagates into the class definition,
#so it works - BUT WHY?!
a = A(None)
a.get = mock_get
b = B('/file1', '/file2')
res = b.foo()
assert not res
現在,奇怪的一點-從代碼內的注釋中可以看出,如果我們將mock_get
分配給該類,它將不會傳播,但是如果我們創建一個實例並將其分配給它,則它會傳播給該類的其他實例。
我想這種行為與mock
內部機制有關,因此對我來說很重要的一點是要理解它,並充分利用此庫的所有豐富功能。
那么,有人知道嗎?
在第一種情況下,我看不到您正在修補get
方法的任何地方。 在調用B
之前,應將模擬值分配給A
的get
方法。 例如,為什么以下測試失敗?:
import mock
mock_get = mock.MagicMock(side_effect=[{'result': 0}, {'result': 1}])
@mock.patch('__main__.A')
def test_foo(MockA):
MockA.get = mock_get
b = B('/file1','/file2')
res = b.foo()
assert not res
MockA.assert_any_call('/file1')
MockA.assert_any_call('/file2')
先前行為的原因是我們忘記修補對象(A)的返回值,在本例中為MockA
,而不是對象本身( MockA
)。 A
對象是實例化A
類的結果,您應該通過A
類的return_value
訪問方法。 在您的示例中,將類似於以下內容:
import mock
mock_get = mock.MagicMock(side_effect=[{'result': 0}, {'result': 1}])
@mock.patch('__main__.A')
def test_foo(MockA):
MockA.return_value.get = mock_get
b = B('/file1','/file2')
res = b.foo()
assert res
MockA.assert_any_call('/file1')
MockA.assert_any_call('/file2')
您可以查看以下一些帖子,以獲取有關常見python單元測試陷阱的更多信息:
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.