2015-12-22 45 views
3

我是新來的模擬Python。我想知道如何在使用另一個類的方法進行測試時替換(模擬)一個類方法,並知道原始方法會更改自身的某些屬性而不返回任何值。例如:在Python中嘲笑類方法並更改某些對象屬性

def some_method(self): 
    self.x = 4 
    self.y = 6 

所以在這裏我不能只是改變模擬的return_value。我試圖定義一個新的函數(應該替換原來的),並將其作爲side_effect給模擬。但是我怎樣才能讓類中的對象的模擬函數改變屬性。 這裏是我的代碼:

@patch('path.myClass.some_method') 
def test_this(self,someMethod): 

    def replacer(self): 
     self.x = 5 
     self.y = 16 

some_method.side_effect = replacer 

那麼,如何Python的現在明白替代品的self說法?這是測試類的自我,還是自我作爲被測試類的對象?

回答

6

道歉提前如果我不明白你正在嘗試做的,但我認爲這可能工作:

import unittest 
from unittest.mock import patch 

class MyClass: 

    def __init__(self): 
     self.x = 0 
     self.y = 0 

    def some_method(self): 
     self.x = 4 
     self.y = 6  

class OtherClass: 

    def other_method(self): 
     self.x = 5 
     self.y = 16 

class MyTestClass(unittest.TestCase): 

    @patch('__main__.MyClass.some_method', new=OtherClass.other_method) 
    def test_patched(self): 
     a = MyClass() 
     a.some_method() 
     self.assertEqual(a.x, 5) 
     self.assertEqual(a.y, 16) 

    def test_not_patched(self): 
     a = MyClass() 
     a.some_method() 
     self.assertEqual(a.x, 4) 
     self.assertEqual(a.y, 6) 

if __name__ == "__main__": 
    unittest.main() 

這將替換some_method()與修補時,它設置不同的值other_method()爲屬性X,Y,並在測試運行時,它給出的結果:

.. 
---------------------------------------------------------------------- 
Ran 2 tests in 0.020s 

OK 

編輯:回答有關如何測試函數內部沒有做嘲笑的一類問題...

def test_inside_patch(self): 
    def othermethod(self): 
     self.x = 5 
     self.y = 16 
    patcher = patch('__main__.MyClass.some_method', new=othermethod) 
    patcher.start() 
    a = MyClass() 
    a.some_method() 
    self.assertEqual(a.x, 5) 
    self.assertEqual(a.y, 16) 
    patcher.stop() 

確保您在修補程序上調用start()和stop(),否則您可能會遇到修補程序處於活動狀態而您不希望它發生的情況。請注意,爲了在測試代碼函數中定義模擬函數,我沒有使用補丁作爲裝飾器,因爲在補丁中使用'new'關鍵字之前必須定義模擬函數。如果你想使用補丁作爲裝飾器,你必須在補丁前定義模擬函數,在MyTestClass中定義它也可以,但似乎你真的想在你的測試函數代碼中定義模擬函數。

編輯:4點的方法,我看這樣做補充總結......這些

# first way uses a class outside MyTest class 
class OtherClass: 
    def other_method(self): 
     ... 

class MyTest(unittest.TestCase): 

    @patch('path_to_MyClass.some_method', new=OtherClass.other_method) 
    def test_1(self) 
     ... 

    # 2nd way uses class defined inside test class  
    class MyOtherClass: 
     def other_method(self): 
      ... 
    @patch('path_to_MyClass.some_method', new=MyOtherClass.other_method)  
    def test_2(self): 
     ... 

    # 3rd way uses function defined inside test class but before patch decorator 
    def another_method(self): 
     ... 
    @patch('path_to_MyClass.some_method', new=another_method)  
    def test_3(self): 
     ... 

    # 4th way uses function defined inside test function but without a decorator 
    def test_4(self): 
     def yet_another_method(self): 
      ... 
     patcher = patch('path_to_MyClass.some_method', new=yet_another_method) 
     patcher.start() 
     ... 
     patcher.stop() 

無使用side_effect,但他們都解決嘲諷一個類的方法,改變一些屬性的問題。您選擇哪一個取決於應用程序。

+0

謝謝你的回答。這非常有幫助。但是,在這個新班級中創造一個新班級,然後是一種新方法是否有必要?難道我只是在測試代碼中定義other_method,然後將其作爲side_effect賦予它? –

+0

@AhmedAyadi是的,可以在測試函數代碼中定義模擬函數,但我不確定使用side_effect。看我的編輯到我的文章。 PS。如果這個答案解決了你的問題,請接受它,謝謝! –

+0

非常感謝:)這確實回答了我的問題 –