2016-08-10 35 views
3

在爲我的應用程序編寫單元測試時,我一直使用@mock.patch@patch.object裝飾器。但是現在,當我使用裝飾器進行一些單元測試時,我收到一個錯誤'TypeError:靜態方法對象不是迭代器'。在Python中使用'@ patch.object'和'with patch.object'有什麼區別?

但使用相同的代碼,如果我使用mock.patch.objectmock.patch.object,一切正常。

例如,在我的測試類我有這樣的方法:

@staticmethod 
def my_mock(): 
    ...do something 

當我嘗試以下的單元測試

@mock.patch('mypackage.mymodule.my_method', side_effect=my_mock) 
def test_something(self, my_method_mocked): 
    ...test something 

我接收之前'類型錯誤規定錯誤消息:靜態方法對象不是迭代器'。

但是當我嘗試這樣

def test_something(self): 
    with patch.object(mymodule, "my_method") as mocked_method: 
     mocked_method.side_effect = self.my_mock 
     ...test something 

然後一切完美的作品。

我讀過關於模擬和單元測試的Python文檔,但是我找不到任何這種行爲的解釋。

使用修飾器模式模式有什麼區別?在哪裏我可以找到更多關於這個?

只是爲了更清楚,這是我的代碼結構:

class TestClass(unittest.TestCase): 

    @staticmethod 
    def my_mock(): 
    ...mock 
     return service 

    # doesn't work 
    @mock.patch('mypackage.mymodule.my_method', side_effect=my_mock) 
    def test_something(self, my_method_mocked): 
     ...test something 

    # work 
    def test_something(self): 
    with patch.object(mymodule, "my_method") as mocked_method: 
     mocked_method.side_effect = self.my_mock 
     ...test something 

這就是爲什麼我不能做TestClass.my_mock。如果我這樣做,我會收到參考錯誤。

回答

1

您看到Python的描述符協議的影響。差異不在於你如何呼叫patch,而是在每種情況下分配給side_effect屬性的值。

class A(object): 
    @staticmethod 
    def my_mock(): 
     pass 

    print type(my_mock) # As in your decorator case 

# As in your context manager case 
print type(A.my_mock) 
print type(A().my_mock) 

如果你運行這段代碼,你會看到print聲明類聲明輸出<type 'staticmethod'>裏面,因爲你有方法本身的參考。

另外兩個print語句輸出<type 'function'>因爲你不要有參考方法;您可以參考方法__get__方法的返回值。這兩個調用相當於

print type(A.__dict__['my_mock'].__get__(A)) 
print type(A.__dict__['my_mock'].__get__(A())) 

對於如何描述符用來實現三種方法(靜態,類和實例)更詳細的討論見https://docs.python.org/2/howto/descriptor.html


實際的錯誤來約,因爲patch預計可贖回爲side_effect參數的值,而做不到這一點,它需要返回值的迭代。 A staticmethod對象既不可調用也不可迭代。 (試一試:A.__dict__['my_mock']()

爲了確保您獲得該功能,您需要通過該類訪問該方法。

class Foo(object): 
    @staticmethod 
    def my_mock(): 
     "whatever it does" 

@mock.patch('mypackage.mymodule.my_method', side_effect=Foo.my_mock) 
def test_something(self, my_method_mocked): 
    ...test something 
+0

但是,當他們是'@ classmethod'時,我只能引用像這個Foo.my_mock這樣的方法。 '@ staticmethod'不起作用。 –

+0

'Foo.my_mock'完全是*您如何訪問靜態方法。靜態方法和類方法之間的唯一區別是靜態方法不會將類的引用作爲參數。 – chepner

+0

如果我嘗試像''Foo.my_mock''那樣使用'my_mock'作爲靜態方法,那麼我得到一個錯誤,說我無法做到這一點。但是我聲明'my_mock'是一個類方法,比我可以使用它。 –

0

我想你只需要添加類名

class mymodule: 
    @staticmethod 
    def my_mock(): 
     ...do something 
... 

@mock.patch('mypackage.mymodule.my_method', side_effect=mymodule.my_mock) 
def test_something(self, my_method_mocked): 
    ...test something 
相關問題