太棒了!我們驗證了上傳服務(wù)成功調用了實(shí)例的rm方法。你是不是注意到這當中有意思的地方了?這種修補機制實(shí)際上取代了我們的測試方法的刪除服務(wù)實(shí)例的rm方法。這意味著(zhù),我們實(shí)際上可以檢查該實(shí)例本身。如果你想了解更多,可以試著(zhù)在模擬測試的代碼中下斷點(diǎn)來(lái)更好的認識這種修補機制是如何工作的。
陷阱:裝飾的順序
當使用多個(gè)裝飾方法來(lái)裝飾測試方法的時(shí)候,裝飾的順序很重要,但很容易混亂?;旧?,當裝飾方法唄映射到帶參數的測試方法中時(shí),裝飾方法的工作順序是反向的。比如下面這個(gè)例子:
1 2 3 4 5 |
@mock.patch('mymodule.sys') @mock.patch('mymodule.os') @mock.patch('mymodule.os.path') def test_something(self, mock_os_path, mock_os, mock_sys): pass |
注意到了嗎,我們的裝飾方法的參數是反向匹配的? 這是有部分原因是因為Python的工作方式。下面是使用多個(gè)裝飾方法的時(shí)候,實(shí)際的代碼執行順序:
1 |
patch_sys(patch_os(patch_os_path(test_something))) |
由于這個(gè)關(guān)于sys的補丁在最外層,因此會(huì )在最后被執行,使得它成為實(shí)際測試方法的最后一個(gè)參數。請特別注意這一點(diǎn),并且在做測試使用調試器來(lái)保證正確的參數按照正確的順序被注入。
選項2: 創(chuàng )建模擬測試接口
我們可以在UploadService的構造函數中提供一個(gè)模擬測試實(shí)例,而不是模擬創(chuàng )建具體的模擬測試方法。 我推薦使用選項1的方法,因為它更精確,但在多數情況下,選項2是必要的并且更加有效。讓我們再次重構我們的測試實(shí)例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
#!/usr/bin/env python # -*- coding: utf-8 -*- from mymodule import RemovalService, UploadService import mock import unittestclass RemovalServiceTestCase(unittest.TestCase): @mock.patch('mymodule.os.path') @mock.patch('mymodule.os') def test_rm(self, mock_os, mock_path): # instantiate our service reference = RemovalService() # set up the mock mock_path.isfile.return_value = False reference.rm("any path") # test that the remove call was NOT called. self.assertFalse(mock_os.remove.called, "Failed to not remove the file if not present.") # make the file 'exist' mock_path.isfile.return_value = True reference.rm("any path") mock_os.remove.assert_called_with("any path") class UploadServiceTestCase(unittest.TestCase): def test_upload_complete(self, mock_rm): # build our dependencies mock_removal_service = mock.create_autospec(RemovalService) reference = UploadService(mock_removal_service) # call upload_complete, which should, in turn, call `rm`: reference.upload_complete("my uploaded file") # test that it called the rm method mock_removal_service.rm.assert_called_with("my uploaded file") |
原文轉自:http://www.diggerplus.org/archives/2704