簡體   English   中英

python模擬:替換類方法

[英]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之前,應將模擬值分配給Aget方法。 例如,為什么以下測試失敗?:

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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM