python mock
如何不靠耐心測試
通常,我們編寫的軟件會直接與那些我們稱之為“骯臟的”服務交互。通俗地說,服務對我們的應用來說是至關重要的,它們之間的交互是我們設計好的,但這會帶來我們不希望的副作用——就是那些在我們自己測試的時候不希望的功能。
比如,可能我們正在寫一個社交軟件并且想測試一下“發布到Facebook的功能”,但是我們不希望每次運行測試集的時候都發布到Facebook上。
Python的unittest庫中有一個子包叫unittest.mock——或者你把它聲明成一個依賴,簡化為mock——這個模塊提供了非常強大并且有用的方法,通過它們可以模擬或者屏敝掉這些不受我們希望的方面。
注意:mock是最近收錄在Python 3.3標準庫中的;之前發布的版本必須通過 PyPI下載Mock庫。
恐懼系統調用
再舉一個例子,考慮系統調用,我們將在余下的文章中討論它們。不難發現,這些都可以考慮使用模擬:無論你是想寫一個腳本彈出一個CD驅動,或者是一個web服務用來刪除/tmp目錄下的緩存文件,或者是一個socket服務來綁定一個TCP端口,這些調用都是在你單元測試的時候是不被希望的方面。
作為一個開發人員,你更關心你的庫是不是成功的調用了系統函數來彈出CD,而不是體驗每次測試的時候CD托盤都打開。
作為一個開發人員,你更關心你的庫是不是成功調用了系統函數來彈出CD(帶著正確的參數等)。而不是體驗每次測試的時候CD托盤都打開(或者更糟,很多次,當一個單元測試運行的時候,很多測試點都涉及到了彈出代碼)。
同樣地,保持你的單元測試效率和性能意味著要還要保留一些自動化測試之外的“緩慢代碼”,比如文件系統和網絡的訪問。
對于我們的第一個例子,我們要重構一個從原始到使用mock的一個標準Python測試用例。我們將會證明如何用mock寫一個測試用例使我們的測試更智能、更快,并且能暴露更多關于我們的軟件工作的問題。
一個簡單的刪除功能
有時,我們需要從文件系統中刪除文件,因此,我們可以寫這樣的一個函數在Python中,這個函數將使它更容易成為我們的腳本去完成這件事情。
1 2 3 4 5 6 |
#!/usr/bin/env python # -*- coding: utf-8 -*- import os def rm(filename): os.remove(filename) |
很明顯,在這個時間點上,我們的rm方法不提供比基本os.remove方法更多的功能,但我們的代碼將會有所改進,允許我們在這里添加更多的功能。
讓我們寫一個傳統的測試用例,即,不用模擬測試:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
#!/usr/bin/env python # -*- coding: utf-8 -*- from mymodule import rm import os.path import tempfile import unittestclass RmTestCase(unittest.TestCase): tmpfilepath = os.path.join(tempfile.gettempdir(), "tmp-testfile") def setUp(self): with open(self.tmpfilepath, "wb") as f: f.write("Delete me!") def test_rm(self): # remove the file rm(self.tmpfilepath) # test that it was actually removed self.assertFalse(os.path.isfile(self.tempfile), "Failed to remove the file.") |
原文轉自:http://www.diggerplus.org/archives/2704