Python單元測試實(shí)例詳解
本文實(shí)例講述了Python單元測試。分享給大家供大家參考,具體如下:
在Python中進(jìn)行單元測試需要用到自動(dòng)單元測試框架PyUnit,Python2.1及其以后的版本都將PyUnit作為一個(gè)標(biāo)準(zhǔn)模塊(即python的unittest模塊),如果你很out,那么你需要從PyUnit網(wǎng)站下載源碼安裝后才能使用。
一、Python單元測試范例
測試最基本的原理是比較預(yù)期結(jié)果是否與實(shí)際執(zhí)行結(jié)果相同,如果相同則測試成功,否則測試失敗。為了更好地理解自動(dòng)測試框架PyUnit,下面會(huì)以對Widget類進(jìn)行測試為例說明之:
#widget.py #將要被測試的類Widget class Widget: def __init__(self, size = (40, 40)): self._size = size def getSize(self): return self._size def resize(self, width, height): if width < 0 or height < 0: raise ValueError, "illegal size" self._size = (width, height) def dispose(self): pass
二、測試用例TestCase
軟件測試中最基本的組成單元式測試用例(test case),PyUnit使用TestCase類來表示測試用例,并要求所有用于執(zhí)行測試的類都必須從該類繼承。TestCase子類實(shí)現(xiàn)的測試代碼應(yīng)該是自包含的(self contained),即測試用例既可以單獨(dú)運(yùn)行,也可以和其它測試用例構(gòu)成集合共同運(yùn)行。TestCase類中常用的函數(shù)或方法有:
setUp:進(jìn)行測試前的初始化工作。
tearDown:執(zhí)行測試后的清除工作。
failedinfo:表示不成立打印信息faliedinfo,為可選參數(shù)。
self.assertEqual(value1, value2, failedinfo):會(huì)無條件的導(dǎo)致測試失敗,不推薦使用。
self.assertTrue(, failedinfo):斷言value1 == value2。
self.assertFalse(, failedinfo):斷言value為真。
self.assertRaises(ValueError, self.widget.resize, -1, -1):斷言肯定發(fā)生異常,如果沒發(fā)生異常,則為測試失敗。參數(shù)1為異常,參數(shù)2為拋出異常的調(diào)用對象,其余參數(shù)為傳遞給可調(diào)用對象的參數(shù)。
TestCase在PyUnit測試框架中被視為測試單元的運(yùn)行實(shí)體,Python程序員可以通過它派生自定義的測試過程與方法(測試單元),利用Command和Composite設(shè)計(jì)模式,多個(gè)TestCase還可以組合成測試用例集合。PyUnit測試框架在運(yùn)行一個(gè)測試用例時(shí),TestCase子類定義的setUp()
、runTest()
和tearDown()
方法被依次執(zhí)行,最簡單的測試用例只需要覆蓋runTest()
方法來執(zhí)行特定的測試代碼就可以了。
1、靜態(tài)方法
一個(gè)測試用例只對軟件模塊中一個(gè)方法進(jìn)行測試,采用覆蓋runTest()方法來構(gòu)造測試用例,這在PyUnit中稱之為靜態(tài)方法,舉例說明如下:
#static.py from widget import Widget import unittest #執(zhí)行測試的類 class WidgetTestCase(unittest.TestCase): def runTest(self): widget = Widget() self.assertEqual(widget.getSize(), (40, 40)) #測試 if __name__ == "__main__": testCase = WidgetTestCase() testCase.runTest()
如果采用靜態(tài)方法,Python程序員就不得不為每個(gè)要測試的方法編寫一個(gè)測試類,該類通過覆蓋runTest()
方法來執(zhí)行測試,并在每個(gè)測試類中生成一個(gè)待測試的對象,這樣會(huì)非常繁瑣與笨拙。
2、動(dòng)態(tài)方法
鑒于靜態(tài)方法的缺陷,PyUnit提供了另一種高帥富的解決方法,即動(dòng)態(tài)方法,只編寫一個(gè)測試類來完成對整個(gè)軟件模塊的測試,這樣對象的初始化工作可以在setUp()
方法中完成,而資源的釋放則可以在tearDown()
方法中完成,舉例說明如下:
#dynamic.py from widget import Widget import unittest class WidgetTestCase(unittest.TestCase): def setUp(self): self.widget = Widget() def tearDown(self): self.widget.dispose() self.widget = None def testSize(self): self.assertEqual(self.widget.getSize(), (40, 40)) def testResize(self): self.widget.resize(100, 100) self.assertEqual(self.widget.getSize(), (100, 100))
動(dòng)態(tài)方法不再覆蓋runTest()方法,而是為測試類編寫多個(gè)測試方法,按照慣例這些方法通常以test開頭但這不是必須的,在創(chuàng)建TestCase子類的實(shí)例時(shí)必須給出測試方法的名稱來為PyUnit測試框架指明運(yùn)行該測試用例時(shí)應(yīng)該調(diào)用測試類中的哪些方法,這通常會(huì)結(jié)合測試用例集TestSuite一起使用。
三、測試用例集TestSuite
完整的單元測試很少只執(zhí)行一個(gè)測試用例,開發(fā)人員通常需要編寫多個(gè)測試用例才能對某一軟件功能進(jìn)行比較完成的測試,這些相關(guān)的測試用例稱為一個(gè)測試用例集,在PyUnit中是用TestSuite類來表示的。PyUinit測試框架允許Python程序員在單元測試代碼中定義一個(gè)名為suite()的全局函數(shù),并將其作為整個(gè)單元測試的入口,PyUnit通過調(diào)用它來完成整個(gè)測試過程:
def suite(): suite = unittest.TestSuite() suite.addTest(WidgetTestCase("testSize")) suite.addTest(WidgetTestCase("testResize")) return suite 也可以直接定義一個(gè)TestSuite的子類,并在其初始化方法__init__中完成所有測試用例的添加: class WidgetTestSuite(unittest.TestSuite) def __init__(self): unittest.TestSuite.__init__(self, map(WidgetTestCase, ("testSize", "testResize"))) 這樣只需要在suite()方法中返回該類的一個(gè)實(shí)例就可以了: def suite(): return WidgetTestSuite()
在PyUnit測試框架中,TestSuite類可以看成是TestCase類的一個(gè)容器,用來對多個(gè)測試用例進(jìn)行組織,這樣多個(gè)測試用例可以自動(dòng)在一次測試中全部完成。事實(shí)上,TestSuite除了可以包含TestCase外,也可以包含TestSuite,從而可以構(gòu)成一個(gè)更龐大的測試用例集:
suite1 = mysuite1.TheTestSuite() suite2 = mysuite2.TheTestSuite() alltests = unittest.TestSuite((suite1, suite2))
四、實(shí)施測試TestRunner
編寫測試用例(TestCase)并將它們組織成測試用例集(TestSuite)的最終目的只有一個(gè):實(shí)施測試并獲得最終結(jié)果。PyUnit使用TestRunner類作為測試用例的基本執(zhí)行環(huán)境,來驅(qū)動(dòng)整個(gè)單元測試過程。但是Python開發(fā)人員在進(jìn)行單元測試時(shí)一般不直接使用TestRunner類,而是使用其子類TextTestRunner來完成測試,并將測試結(jié)果以文本方式顯示出來。舉例說明如下:
#text_runner.py from widget import Widget import unittest #執(zhí)行測試的類 class WidgetTestCase(unittest.TestCase): def setUp(self): self.widget = Widget() def tearDown(self): self.widget.dispose() self.widget = None def testSize(self): self.assertEqual(self.widget.getSize(), (40, 40)) def testResize(self): self.widget.resize(100, 100) self.assertEqual(self.widget.getSize(), (100, 100)) #測試 if __name__ == "__main__": #構(gòu)造測試集 suite = unittest.TestSuite() suite.addTest(WidgetTestCase("testSize")) suite.addTest(WidgetTestCase("testResize")) #執(zhí)行測試 runner = unittest.TextTestRunner() runner.run(suite)
使用如下命令執(zhí)行該單元測試:
$python text_runner.py
默認(rèn)情況下,TextTestRunner將結(jié)果輸出到sys.stdout/sys.stderr上,但是如果在創(chuàng)建TextTestRunner類實(shí)例時(shí)將一個(gè)文件對象傳遞給了構(gòu)造函數(shù),則輸出結(jié)果將被重定向到該文件中。
五、大道至簡main()
PyUnit模塊中定義了一個(gè)名為main的全局方法,使用它可以很方便地將一個(gè)單元測試模塊變成可以直接運(yùn)行的測試腳本,main()方法使用TestLoader類來搜索所有包含在該模塊中的測試方法,并自動(dòng)執(zhí)行它們。如果Python程序員能夠按照約定(以test開頭)來命令所有的測試方法,那么只需要在測試模塊的最后加入如下幾行代碼即可:
if __name__ == "__main__": unittest.main()
下面是利用main()方法來進(jìn)行測試的完整例子:
#main_runner.py from widget import Widget import unittest #執(zhí)行測試的類 class WidgetTestCase(unittest.TestCase): def setUp(self): self.widget = Widget() def tearDown(self): self.widget.dispose() self.widget = None def testSize(self): self.assertEqual(self.widget.getSize(), (40, 40)) def testResize(self): self.widget.resize(100, 100) self.assertEqual(self.widget.getSize(), (100, 100)) #測試 if __name__ == "__main__": unittest.main()
使用如下命令執(zhí)行上面的單元測試:
$python main_runner.py
如上這樣將執(zhí)行WidgetTestCase中的所有測試方法,但是如果只想執(zhí)行testSize()方法,則可以如下這般:
$python main_runner.py WidgetTestCase.testSize
如果在單元測試腳本中定義了TestSuite,還可以指定要運(yùn)行的測試集,使用-h參數(shù)可以查看運(yùn)行該腳本所有可能用到的參數(shù):
$python main_runner.py -h
需要注意的是:PyUnit的TestCase中如果有多個(gè)test_xxx,則默認(rèn)按照xxx的字母順序執(zhí)行測試用例函數(shù),如果test_xxx之間有依賴關(guān)系的話就會(huì)出錯(cuò),解決方法有二:1、解耦;2、編寫xxx函數(shù)時(shí)人為地按字母順序。
當(dāng)然,如果你安裝了Python 2.7.2及以上版本,你還可以利用discover函數(shù)來自動(dòng)發(fā)現(xiàn)并執(zhí)行測試用例:
$python2.7 -m unittest discover
更多關(guān)于Python單元測試的資料可以參看這里,還有這里。
更多Python相關(guān)內(nèi)容感興趣的讀者可查看本站專題:《Python入門與進(jìn)階經(jīng)典教程》、《Python字符串操作技巧匯總》、《Python列表(list)操作技巧總結(jié)》、《Python編碼操作技巧總結(jié)》、《Python數(shù)據(jù)結(jié)構(gòu)與算法教程》、《Python函數(shù)使用技巧總結(jié)》及《Python文件與目錄操作技巧匯總》
希望本文所述對大家Python程序設(shè)計(jì)有所幫助。
相關(guān)文章
Python如何使用k-means方法將列表中相似的句子歸類
這篇文章主要介紹了Python如何使用k-means方法將列表中相似的句子聚為一類,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-08-08django與小程序?qū)崿F(xiàn)登錄驗(yàn)證功能的示例代碼
這篇文章主要介紹了django與小程序?qū)崿F(xiàn)登錄驗(yàn)證功能的示例代碼,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-02-02python gensim使用word2vec詞向量處理中文語料的方法
這篇文章主要介紹了python gensim使用word2vec詞向量處理中文語料的方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-07-07Python數(shù)據(jù)類型中的“冒號(hào)“[::]——分片與步長操作示例
這篇文章主要介紹了Python數(shù)據(jù)類型中的“冒號(hào)“[::]——分片與步長操作,結(jié)合實(shí)例形式分析了Python基本數(shù)據(jù)類型中的分片與步長使用方法及相關(guān)操作技巧,需要的朋友可以參考下2018-01-01學(xué)習(xí)createTrackbar的使用方法及步驟
這篇文章主要為大家介紹了學(xué)習(xí)createTrackbar的使用方法及步驟,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步2021-10-10python使用seaborn繪圖直方圖displot,密度圖,散點(diǎn)圖
這篇文章主要介紹了python使用seaborn繪圖直方圖displot,密度圖,散點(diǎn)圖,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下2022-07-07pywinauto自動(dòng)化測試使用經(jīng)驗(yàn)
本文主要介紹了pywinauto自動(dòng)化測試使用經(jīng)驗(yàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-03-03Android申請相機(jī)權(quán)限和讀寫權(quán)限實(shí)例
大家好,本篇文章主要講的是Android申請相機(jī)權(quán)限和讀寫權(quán)限實(shí)例,感興趣的同學(xué)趕快來看一看吧,對你有幫助的話記得收藏一下2022-02-02