本文實例講述了python單元測試unittest用法。分享給大家供大家參考。具體分析如下:
單元測試作為任何語言的開發者都應該是必要的,因為時隔數月后再回來調試自己的復雜程序時,其實也是很崩潰的事情。雖然會很快熟悉內容,但是修改和調試將是一件痛苦的事情,如果你在修改了代碼后出現問題的話,而單元測試可以幫助我們很快準確的定位到問題的位置,出現問題的模塊和單元。所以這是一件很愉快的事情,因為我們知道其它修改或沒有修改的地方仍然是正常工作的,而我們目前的唯一問題就是搞定眼前這個有點問題的“家伙”。所以工作會在輕松中開始,并且很快將會結束,因為你已經知道很多信息了。
單元測試自然是對程序中最小的可測試模塊--函數來進行測試;因為單元測試的對象是函數,也就是說你得被測試對象一定要有輸出結果,哪怕就是異常輸出,也得有輸出,以便單元測試模塊能夠捕獲返回值,并且與預期值進行比較,從而得出測試通過與否。
單元測試的加載方式有2種:一種是通過unittest.main()來啟動單元測試的測試模塊;一種是添加到testsuite集合中再加載所有的被測試對象,而testsuit里存放的就是單元測試的用例,下面分別列出了2種方法的使用。
1.1 測試模塊中的函數:
被測模塊:
1
2
3
4
5
6
|
#!/usr/bin/env python #encoding: utf-8 def sum ( x, y): return x + y def sub( x, y): return x - y |
單元測試模塊:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
#!/usr/bin/env python #encoding: utf-8 import unittest import myclass class mytest(unittest.TestCase): ##初始化工作 def setUp( self ): pass #退出清理工作 def tearDown( self ): pass #具體的測試用例,一定要以test開頭 def testsum( self ): self .assertEqual(myclass. sum ( 1 , 2 ), 2 , 'test sum fail' ) def testsub( self ): self .assertEqual(myclass.sub( 2 , 1 ), 1 , 'test sub fail' ) if __name__ = = '__main__' : unittest.main() |
測試結果:【F表示一個fail, F前的點表示一個通過,有E的話表示程序自身異常】
1
2
3
4
5
6
7
8
9
10
11
|
.F = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = FAIL: testsum (__main__.mytest) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Traceback (most recent call last): File "C:\Users\xiaowu\workspace\mypython\unitTest.py" , line 19 , in testsum self .assertEqual(myclass. sum ( 1 , 2 ), 2 , 'test sum fail' ) AssertionError: test sum fail - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Ran 2 tests in 0.001s FAILED (failures = 1 ) |
1.2 測試模塊類中的函數:
被測模塊:
1
2
3
4
5
6
7
8
9
|
#!/usr/bin/env python #encoding: utf-8 class myclass: def __init__( self ): pass def sum ( self , x, y): return x + y def sub( self , x, y): return x - y |
單元測試模塊:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
#!/usr/bin/env python #encoding: utf-8 import unittest import myclass class mytest(unittest.TestCase): ##初始化工作 def setUp( self ): self .tclass = myclass.myclass() ##實例化了被測試模塊中的類 #退出清理工作 def tearDown( self ): pass #具體的測試用例,一定要以test開頭 def testsum( self ): self .assertEqual( self .tclass. sum ( 1 , 2 ), 3 ) if __name__ = = '__main__' : unittest.main() |
運行結果:
1
2
3
4
|
. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Ran 1 test in 0.000s OK |
這種方式執行單個測試文件時使用-v參數可以獲得更多的測試結果信息。如:mytest.py -v
2 加載測試套件
好吧,在運用測試套件進行單元測試之前,我想還是稍微研究一下unittest模塊的內容有哪些,其大概的運行方式是什么樣的。而后在給出根據各種情況如何制定單元測試套件。
首先,自然是查看unittest模塊有哪些成員啦!
1
2
3
4
5
6
7
8
|
>> import unittest >> dir (unittest) [ 'FunctionTestCase' , 'TestCase' , 'TestLoader' , 'TestProgram' , 'TestResult' , 'Tes tSuite ', ' TextTestRunner ', ' _CmpToKey ', ' _TextTestResult ', ' _WritelnDecorator', '__all__' , '__author__' , '__builtins__' , '__doc__' , '__email__' , '__file__' , '__ metaclass__ ', ' __name__ ', ' __package__ ', ' __unittest ', ' __version__ ', ' _makeLoad er ', ' _strclass ', ' defaultTestLoader ', ' findTestCases ', ' getTestCaseNames ', ' mai n ', ' makeSuite ', ' os ', ' sys ', ' time ', ' traceback ', ' types'] |
可以看到其自身的成員也不是很多,大概包括有:
1
2
3
|
[ 'FunctionTestCase' , 'TestCase' , 'TestLoader' , 'TestProgram' , 'TestResult' , 'TestSuite' , 'TextTestRunner' , '_CmpToKey' , '_TextTestResult' , '_WritelnDecorator' , 'defaultTestLoader' , 'findTestCases' , 'getTestCaseNames' , 'main' , 'makeSuite' ] |
好吧,我們大概看看具體都是干什么的
1
2
3
4
5
6
|
>>memblist = [ 'FunctionTestCase' , 'TestCase' , 'TestLoader' , 'TestProgram' , 'TestResult' ,\ 'TestSuite' , 'TextTestRunner' , 'defaultTestLoader' , 'findTestCases' , 'getTestCaseNames' , \ 'main' , 'makeSuite' ] >> for memb in memblist: .. cur = getattr (unittest, memb) .. print help (cur) |
'FunctionTestCase':函數測試用例,即給一個函數作為參數,返回一個testcase實例,可選參數有set-up,tear-down方法
'TestCase':所有測試用例的基本類,給一個測試方法的名字,返回一個測試用例實例
'TestLoader':測試用例加載器,其包括多個加載測試用例的方法。返回一個測試套件
loadTestsFromModule(self, module)--根據給定的模塊實例來獲取測試用例套件
loadTestsFromName(self, name, module=None)
--根據給定的字符串來獲取測試用例套件,字符串可以是模塊名,測試類名,測試類中的測試方法名,或者一個可調用的是實例對象
這個實例對象返回一個測試用例或一個測試套件
loadTestsFromNames(self, names, module=None) --和上面功能相同,只不過接受的是字符串列表
loadTestsFromTestCase(self, testCaseClass)--根據給定的測試類,獲取其中的所有測試方法,并返回一個測試套件
'TestProgram':命令行進行單元測試的調用方法,作用是執行一個測試用例。其實unittest.main()方法執行的就是這個命令,
而這個類實例時默認加載當前執行的作為測試對象,
原型為 __init__(self, module='__main__', defaultTest=None, argv=None, testRunner=xx, testLoader=xx)
其中module='__main__'就是默認加載自身
'TestResult':測試用例的結果保存實例,通常有測試框架調用
'TestSuite':組織測試用例的實例,支持測試用例的添加和刪除,最終將傳遞給testRunner進行測試執行
'TextTestRunner':進行測試用例執行的實例,其中Text的意思是以文本形式顯示測試結果。顯示測試名稱,即完成的測試結果,其過同執行單元測試腳本時添加-v參數
'defaultTestLoader':其實就是TestLoader
'findTestCases', 'getTestCaseNames':這個2個就不用解釋了
'main': 其實就是TestProgram
'makeSuite':通常是由單元測試框架調用的,用于生產testsuite對象的實例
至此,我們知道了。其實整個單元測試框架的邏輯出來了。分三步走:第一步testloader根據傳入的參數獲得相應的測試用例,即對應具體的測試方法,
然后makesuite在把所有的測試用例組裝成testsuite,最后把testsiute傳給testrunner進行執行。
而我們通常執行的unittest.main(),其實就是unittest.testprom方法,其執行的功能就是上面分析的三步,在第一步中其傳入的參數是自身的模塊__main__;
在第二步中把自身模塊中的所有測試類中中的測試方法提取出來,并生成測試套件;最后再把測試套件傳遞給testrunner進行具體的測試。
最后給出一個完整的單元測試組織代碼,把該代碼放到單元測試用例文件的同一個目錄后執行該腳本,即可執行所有的測試用例文件。
【測試用例文件必須為test開頭,如:testxxx.py, 當然這個文件本身是一個單元測試的文件】
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
#!/usr/bin/env python #encoding: utf-8 #該代碼源自深入python import unittest import myclass import re import os import sys def testAllinCurrent(): path = os.path.abspath(os.path.dirname(sys.argv[ 0 ])) files = os.listdir(path) test = re. compile ("test\.py{ 1 }quot;, re.IGNORECASE) files = filter (test.search, files) filenameToModuleName = lambda f: os.path.splitext(f)[ 0 ] moduleNames = map (filenameToModuleName, files) modules = map ( __import__ , moduleNames) load = unittest.defaultTestLoader.loadTestsFromModule return unittest.TestSuite( map (load, modules)) if __name__ = = "__main__" : unittest.main(defaultTest = "regressionTest" ) |
希望本文所述對大家的Python程序設計有所幫助。