python之單元測試
一. 什麽是單元測試?單元測試的對象是什麽?
1: 什麽是單元測試?
按照定義,單元測試就是對單個模塊或者單個類或者單個函數進行測試,一般是開發做的,按照階段分,一般就是單元測試、集成測試、系統測試、驗收測試
2: 為什麽要做單元測試?
1) 單元測試之後,才是集成測試,單個單個的功能模塊測試通過之後,才能把單個功能模塊集成起來做集成測試,為了從底層發現bug,減少合成後出現的問題
2) 越早發現bug越好,這樣可以早點發現問題,不然問題累計到後面,如果做錯了就要推倒重來,對於時間和經費來說,是非常浪費的!
3) 對我們測試來說,我們做單元測試是為了執行測試用例
二. 單元測試的語法介紹
1: 引入自帶的單元測試類: import unittest
創建一個測試類,來測試你要測試的目標對象: class TestMath(unittest.TestCase)
2: 引入你要測試的代碼模塊或者是類名: from class_4_test import add
3: 創建單元測試用例來對測試目標進行測試: def test_add(self)
語法:函數用test開頭,然後拼接下劃線,再加函數名,裏面的內容就是創建實例來調用方法
4: 引入斷言,對測試結果進行判斷處理
self.assertEqual(實際結果,期望結果,如果出錯出錯處理)
self.assertEqual(result_add, 6, "答案不等於6,所以答案是錯誤的!")
5: 引入異常判斷,對測試用例進行異常判斷處理: try...except
錯誤基類:AssertionError
6: 引入測試集,方便批量進行單元測試
完整的單元測試很少只執行一個測試用例,開發人員通常需要編寫多個測試用例才能對某一軟件功能進行比較完全的測試,這些相關的測試用例稱為一個測試用例集,用TestSuite類來表示,用到的是TestSuite(),用addTest執行測試集,用到的是TextTestRunner(),用runner.run(suite)
7: 單元測試參數化(少量數據,十組以內)
安裝:pip install parameterized #通過pip安裝,記得先裝好pip和setuptools這兩個,才能用pip命令
使用:引入parameterized
from parameterized import parameterized
使用範例:
class TestMath(unittest.TestCase): @parameterized.expand([ ("01", 1, 1, 2), ("02", 2, 2, 4), ("03", 3, 3, 6), ]) def test_add(self.name, a, b, c): self.assertEqual(Math(a, b).add(), c) print("測試數據是: ", name)
有關parameterized詳細內容請查看https://github.com/wolever/parameterized
8: 測試報告,引入htmlreport模板
1. 單元測試後生成測試報告。前提條件,把測試報告模板HTMLTestRunner.py放在python Lib目錄下
import htmlreport import time #關鍵代碼 suite = unittest.TestSuite() #一個對象,集合所有的單元測試用例 suite.addTest(TestMathFunc("test_add")) ... #執行測試集合 now = time.strftime("%Y-%m-%d_%H_%M_%S") filepath = "pyResult" + now + ".html" #在文件名中加入時間 fp = open(filepath, "wb") #wb表示二進制文件的寫操作 #生成報告的Title,描述 runner = HTMLTestRunner.HTMLTestRunner(stream=fp, title="Python Test Report", description="This is Python Report") runner.run(suite)
9: 舉例
import unittest from ... import ... #引入你要測試的模塊或者是類,打個比方,這裏寫了一個Math類,裏面有加法add,減法sub函數 class TestMath(unittest.TestCase): def setUp(self): #初始化工作,這裏面做初始操作 pass def test_add(self): #註意這裏必須以test_開頭 #寫測試代碼 t = Math() #先實例化Math類 result = t.add(5, 6) self.assertEqual(result, "期望值", "加法運行出錯,期望值不等於實際值") #斷言 def tearDown(self): #掃尾工作,這裏面做單元測試結束後的工作 pass
三. 代碼部分
1: 我們先定義一個需要測試的目標類Math,它的文件名是mathfunc.py
class Math: def add(self, a, b): return a + b def minus(self, a, b): return a - b def multi(self, a, b): return a * b def divide(self, a, b): return a / b
2: 創建測試類,它的文件名是test_mathfunc.py
import unittest from mathfunc import Math #引入你要測試的模塊或者是類,打個比方,這裏寫了一個Math類,裏面有加法add,減法sub函數 class TestMath(unittest.TestCase): def setUp(self): #初始化工作,這裏面做初始操作 pass def test_add(self): #註意這裏必須以test_開頭 try: t = Math() #先實例化Math類 self.assertEqual(t.add(5, 6), 11, "加法運行出錯,實際值不等於期望值") #斷言 except AssertionError as e: print(e) def test_minus(self): try: t = Math() self.assertEqual(t.minus(6, 3), 3, "減法運行出錯,實際值不等於期望值") except AssertionError as e: print(e) def test_multi(self): try: t = Math() self.assertEqual(t.multi(3, 3), 9, "乘法運行出錯,實際值不等於期望值") except AssertionError as e: print(e) def test_divide(self): try: t = Math() self.assertEqual(t.divide(6, 3), 2.0, "除法運行出錯,實際值不等於期望值") except AssertionError as e: print(e) def tearDown(self): #掃尾工作,這裏面做單元測試結束後的工作 pass
3: 創建測試集,它的文件名為test_suite.py
import unittest from test_mathfunc import TestMath #創建測試集合 suite = unittest.TestSuite() #一個對象,集合所有的單元測試用例 suite.addTest(TestMath("test_add")) suite.addTest(TestMath("test_minus")) suite.addTest(TestMath("test_multi")) suite.addTest(TestMath("test_divide")) #創建一個對象來調用測試集合 runner = unittest.TextTestRunner() runner.run(suite)
4: 參數化@parameterized,傳遞一組數據,我們修改之前的test_mathfunc.py文件
import unittest from mathfunc import Math from parameterized import parameterized class TestMath(unittest.TestCase): def setUp(self): pass @parameterized.expand([ ("01", 1, 1, 2), ("02", 2, 2, 4), ("03", 3, 3, 6), ]) def test_add(self, name, a, b, c): try: m = Math() self.assertEqual(m.add(a, b), c, "加法計算錯誤") except AssertionError as e: print(e) else: print("測試數據是: ", name) @parameterized.expand([ ("04", 3, 1, 2), ("05", 6, 3, 3), ("06", 5, 1, 2), ] ) def test_minus(self, name, a, b, c): try: m = Math() self.assertEqual(m.minus(a, b), c, "減法計算錯誤") except AssertionError as e: print(e) else: print("測試數據是: ", name) @parameterized.expand([ ("07", 3, 3, 9), ("08", 3, 2, 6), ("09", 1, 5, 5), ]) def test_multi(self, name, a, b, c): try: m = Math() self.assertEqual(m.multi(a, b), c, "乘法計算錯誤") except AssertionError as e: print(e) else: print("測試數據是: ", name) @parameterized.expand([ ("10", 5, 2, 2.5), ("11", 4, 1, 4.0), ("12", 10, 5, 2.5), ]) def test_divide(self, name, a, b, c): try: m = Math() self.assertEqual(m.divide(a, b), c, "除法計算錯誤") except AssertionError as e: print(e) else: print("測試數據是: ", name) def tearDown(self): pass
5: 引入htmlreport模板,生成測試報告
import unittest from test_mathfunc import TestMathFunc import HTMLTestRunner import time #創建測試集合 suite.addTest(TestMathFunc("test_minus")) suite.addTest(TestMathFunc("test_multi")) suite.addTest(TestMathFunc("test_divide")) now = time.strftime("%Y-%m-%d_%H_%M_%S") #執行測試用例集合 filepath = "pyResult" + now + ".html" fp = open(filepath, "wb") #生成測試報告的title, 描述 runner = HTMLTestRunner.HTMLTestRunner(stream=fp, title="Python Test Report", description="This is Python Report") runner.run(suite)
python之單元測試