unittest單元測試框架,主要由四部分組成:測試固件、測試用例、測試套件、測試執行器
測試固件(test fixture)
測試固件有兩部分,執行測試前的准備部分setUp(),測試執行完后的清掃部分tearDown()
測試用例(test case)
測試用例中,包含測試固件,具體的測試代碼的函數。測試固件可以不寫,但是至少要有一個以test開頭的函數。
unittest會自動識別test開頭的函數是測試代碼,一定要用小寫的test開頭!,下面看一個實例
在PyCharm中新建一個項目,在下面建一個包叫做lesson_unittest,然后在這個包下面新建一個.py文件叫做lesson_test_fixture1,然后寫下面的代碼
import unittest from io import StringIO class lesson(unittest.TestCase): def setUp(self): self.f = StringIO() print("創建StringIO") def tearDown(self): s = self.f.getvalue() print("讀取StringIO:",s) def test_case1(self): self.f.write("test case 1") print("寫入test case 1") def test_case2(self): self.f.write("test case 2") print("寫入test case 2") if __name__ =='__main__': unittest.main()
所有方法中一定要帶self這個變量
unittest.main()在PyCharm可以不要,如果要在cmd中運行,一定要加上這行
setUp()執行成功之后,不管test中有沒有異常發生,tearDown()都會執行
可以看出上面這個實例在執行每個test之前和之后都會去調用setUp()和tearDown()這個方法
很多時候我們只想執行一次測試固件:比如setUp()中放着連接數據庫操作,多個test case放着不同數據庫操作,然后tearDown()斷開數據連接
使用setUpClass()和tearDownClass()可以的得到這樣的效果,必須被裝飾成classmethod
使用裝飾器@unittest.skip可以跳過某個測試用例不執行
在剛才lesson_unittest包下,再新建一個.py文件叫做lesson_test_fixture2,然后寫下面的代碼
import unittest from io import StringIO class lesson(unittest.TestCase): @classmethod def setUpClass(cls): cls.f = StringIO() print("創建StringIO") @classmethod def tearDownClass(cls): s = cls.f.getvalue() print("讀取StringIO:",s) def test_case1(self): self.f.write("test case 1") print("寫入test case 1") def test_case2(self): self.f.write("test case 2") print("寫入test case 2") if __name__ =='__main__': unittest.main()
測試執行器(test runner)
test runner用來執行加載的測試用例,可以是單個測試用例,也可以是測試套件
一種就是上方實例中的直接使用unittest.main()去執行,會搜索所有以test開頭的測試用例,按照ASCII的順序執行多個用例
另一種就是使用TextTestRunner()方法初始化一個測試執行器,然后使用run()去執行測試套件
runner = unittest.TextTestRunner()
runner.run(suite)
這里suite是指測試套件的實例
測試套件(test suite)
很多測試用例的集合就是測試套件,通過測試套件來管理多個測試用例,會根據用例的加載順序執行用例
使用TestSuite()初始化一個Suite實例
使用addTest()方法加載測試方法到測試套件中,addTest()如果要在傳入別的包下的測試方法: 包名.類名(測試方法函數)
suite = unittest.TestSuite() suite.addTest(lesson('test_case1'))#lesson是類名,test_case1是測試函數 suite.addTest(lesson('test_case2'))#如果是lesson是其他包下的,就是包名.lesson(‘test_case2’) runner = unittest.TextTestRunner() runner.run(suite)
將文章第一個示例中最后一行unittest.main()換成上方代碼執行
使用makeSuite()可以把一個類下面所有測試方法都加載到測試套件中
目前項目路徑應該是這樣的,最上面是項目,然后包,最后是.py文件。一定要有__init__.py文件,不然引用不到
在項目下新建一個.py文件,名字隨便不要帶test,或lesson就行。在項目下新建,不要在包里,不要在包里,不要在包里
import unittest from lesson_unittest.lesson_test_fixture1 import lesson suite = unittest.TestSuite(unittest.makeSuite(lesson)) if __name__=='__main__': runner = unittest.TextTestRunner() runner.run(suite)
可以看到把lesson兩個測試用例都執行了,但是使用makeSuite()還是有些繁瑣。要把寫的所有的類都加到測試套件中
最常用的是使用discover()方法可以把指定路徑下所有測試方法都加載到測試套件中
使用剛才實驗makeSuite()方法的那個.py文件,清空代碼輸入以下代碼
import unittest test_dir = 'D:/PycharmProjects/PythonLesson/lesson_unittest' discover = unittest.defaultTestLoader.discover(test_dir, pattern='lesson*.py') runner = unittest.TextTestRunner() runner.run(discover)
test_dir是指定的路徑,pattern是指定的文件名。pattern參數是定義文件名匹配規則的,可以隨便修改
比如這里lesson*.py是指文件名以lesson開頭的文件
也可以寫成*test*文件帶有test的文件
如果是*lesson.py,那就是指文件名以lesson.py結尾的文件
*起到跟通配符差不多的作用