單元測試的本質
測試函數翻伺,從代碼級別上進行測試
單元測試的框架
python+unittest
unittest模塊
python自帶不需安裝
-
結構
- 寫用例 Testcase --- 方法
- 執(zhí)行用例
- 1.TestSuite 存儲用例 --- 類
- 2.TestLoader 找用例,加載用例,存到1中的TestSuite --- 類
- 對比實際結果 斷言 Assert
- 出具測試報告 TextTestRunner
-
測試自己的類
python基礎之初識類與對象 超繼承示例中的MathMethod類
#測試MathMethod類 from py_0909.super import MathMethod #導入待測的類 import unittest class TestMathMethod(unittest.TestCase):#繼承與unittest的Testcase方法 #編寫測試用例 def test_add_two_positive(self): #測試兩個正數相加 res=MathMethod(1,1).add() #實例化調用待測的方法 print("1+1的結果是:",res) def test_add_two_zero(self): #測試兩個0相加 res = MathMethod(0, 0).add() print("0+0的結果是:", res) def test_add_two_negative(self): #測試兩個負數相加 res = MathMethod(-1, -1).add() print("-1+(-1)的結果是:", res) if __name__ == '__main__': unittest.main() #unitest.main()函數用來測試類中以test開頭的測試用例
運行測試用例的結果:
image -
說明
一個用例是一個函數,不能傳參,只有self關鍵字
所有的用例都是test開頭,test_,例如test_add_two_positive
Testcase默認的執(zhí)行順序是按函數名的ASCII碼
配置測試用例的執(zhí)行順序
如果想測試用例不按默認的執(zhí)行順序彬犯,可以通過TestSuite類向楼、TestLoader類搭配使用配置測試用例執(zhí)行順序
-
TestSuite類說明(command鍵+鼠標左鍵進入)
TestSuite測試套件是由測試用例組成的復合測試。
要使用谐区,請創(chuàng)建testsuite的實例湖蜕,然后添加測試用例實例。使用suite.add('方法名')添加測試用例
添加完測試用例后宋列,將TestSuite傳遞給TextTestRunner
它將按添加順序運行各個測試用例
-
執(zhí)行少量用例時昭抒,配置測試用例順序
#新建一個py文件 import unittest from py_inter0913.unittest_01 import TestMathMethod #導入寫了測試用例的類 #創(chuàng)建TestSuite實例,存儲測試用例 suite=unittest.TestSuite() #構造測試套件 suite.addTest(TestMathMethod('test_add_two_positive')) #添加測試用例,必須傳入參數--函數名 suite.addTest(TestMathMethod('test_add_two_zero')) suite.addTest(TestMathMethod('test_add_two_negative')) #執(zhí)行用例 runner=unittest.TextTestRunner() runner.run(suite)
運行結果: 按我們添加測試用例的順序執(zhí)行
image -
執(zhí)行大量用例的方法炼杖,使用TestLoader
import unittest from py_inter0913.unittest_01 import TestMathMethod #導入寫了測試用例的類 #創(chuàng)建一個加載器 suite=unittest.TestSuite() #創(chuàng)建TestSuite實例灭返,存儲測試用例 loader=unittest.TestLoader() suite.addTest(loader.loadTestsFromTestCase(TestMathMethod)) # 從測試類里去找 import也需要導到模塊處 搭配loadTestsFromModule使用 # from py_inter0913 import unittest_01 # suite.addTest(loader.loadTestsFromModule(unittest_01)) #執(zhí)行用例 runner=unittest.TextTestRunner() runner.run(suite)
-
setUp()和tearDown()
在測試類中添加setUp()、tearDown()方法坤邪,會在單條測試用執(zhí)行開始前和結束后執(zhí)行熙含。
- setUp()、tearDown()是TestCase里的方法艇纺,寫在測試類中怎静,就是方法的重寫。
class TestMathMethod(unittest.TestCase): def setUp(self): print("準備開始執(zhí)行測試用例了") def tearDown(self): print("結束了") #編寫測試用例 def test_add_two_positive(self): #測試兩個正數相加 res=MathMethod(1,1).add() print("1+1的結果是:",res)
- 執(zhí)行順序是:
setUp->testA->tearDown->setUp->testB>tearDown
斷言
斷言就是預期結果黔衡。如果不加斷言蚓聘,沒有結果對比,需要手動去檢查運行的結果是否符合預期员帮。
-
assertEqual()
def assertEqual(self, first, second, msg=None): """Fail if the two objects are unequal as determined by the '==' operator. """
- first 預期結果
- second 實際結果
- msg 出錯時或粮,輸出的錯誤信息,可不填
-
斷言使用
在測試用例中寫入斷言
from py_0909.super import MathMethod #導入待測的類 import unittest #測試MathMethod類 class TestMathMethod(unittest.TestCase): #編寫測試用例 def test_add_two_positive(self): #測試兩個正數相加 res=MathMethod(1,1).add() print("1+1的結果是:",res) self.assertEqual(2,res,"兩個正數相加出錯了") #斷言 def test_add_two_zero(self): #測試兩個0相加 res = MathMethod(0, 0).add() print("0+0的結果是:", res) self.assertEqual(0, res, "兩個0相加出錯了") #斷言 def test_add_two_negative(self): #測試兩個負數相加 res = MathMethod(-1, -1).add() print("-1+(-1)的結果是:", res) self.assertEqual(-2, res, "兩個負數相加出錯了") #斷言 if __name__ == '__main__': unittest.main()
-
其他斷言語法
image -
斷言的異常處理
from py_0909.super import MathMethod #導入待測的類 import unittest #測試MathMethod類 class TestMathMethod(unittest.TestCase): #編寫測試用例 def test_add_two_positive(self): #測試兩個正數相加 res=MathMethod(1,1).add() print("1+1的結果是:",res) try: #斷言的異常處理 self.assertEqual(0,res,"兩個正數相加出錯了") #斷言 except AssertionError as e: print("斷言出錯捞高,錯誤是:{0}".format(e)) #對異常的處理:輸出錯誤語句、存儲到excel等 raise e #異常處理完要拋出去渣锦,否則輸出結果中不會報錯 def test_add_two_zero(self): #測試兩個0相加 res = MathMethod(0, 0).add() print("0+0的結果是:", res) try: self.assertEqual(1, res, "兩個0相加出錯了") #斷言 except AssertionError as e: print("斷言出錯硝岗,錯誤是:{0}".format(e)) raise e def test_add_two_negative(self): #測試兩個負數相加 res = MathMethod(-1, -1).add() print("-1+(-1)的結果是:", res) try: self.assertEqual(-1, res, "兩個負數相加出錯了") #斷言 except AssertionError as e: print("斷言出錯,錯誤是:{0}".format(e)) raise e if __name__ == '__main__': unittest.main()
- 從錯誤的輸出可以知道袋毙,異常的基類是AssertionError型檀。
- 捕獲異常,要對異常進行處理听盖,處理之后胀溺,要將異常拋出,否則在結果報告中皆看,不會報錯仓坞。
raise e
測試報告
-
TextTestRunner
imageTextTestRunner是一個以文本形式展示測試結果的測試運行程序類
- stream 輸出報告的路徑,默認輸出控制臺
- verbosity 控制輸出報告的詳細程度腰吟,從0-2无埃,越來越詳細
import unittest from py_inter0913.unittest_01 import TestMathMethod #導入寫了測試用例的類 suite=unittest.TestSuite() #創(chuàng)建TestSuite實例徙瓶,存儲測試用例 loader=unittest.TestLoader() suite.addTest(loader.loadTestsFromTestCase(TestMathMethod)) #執(zhí)行用例 with open("result.txt","w+") as file: runner=unittest.TextTestRunner(stream=file,verbosity=2) runner.run(suite)
-
HTMLTestRunner
使用unittest自帶的報告不夠美觀。HTMLTestRunner是Python標準庫的unittest模塊的擴展嫉称。它生成易于使用的HTML測試報告侦镇。
- HTMLTestRunner是Python標準庫的unittest模塊的擴展,無法通過pip安裝
- 下載HTMLTestRunner.py放在lib目錄下织阅,下載地址:http://tungwaiyip.info/software/HTMLTestRunner.html
- 導入模塊
import HTMLTestRunner
import HTMLTestRunner import unittest from py_inter0913.unittest_01 import TestMathMethod #導入寫了測試用例的類 suite=unittest.TestSuite() #創(chuàng)建TestSuite實例壳繁,存儲測試用例 loader=unittest.TestLoader() suite.addTest(loader.loadTestsFromTestCase(TestMathMethod)) with open("result.html","wb") as file: runner=HTMLTestRunner.HTMLTestRunner(stream=file, title="MathMethod測試", verbosity=2,) runner.run(suite)
運行之后會發(fā)現報錯:No module named 'StringIO',原因是自己使用python3荔棉,而下載的HTMLTestRunner適用于Python2.X闹炉,需要自己對模塊進行修改。
參考文檔:https://www.bbsmax.com/A/QW5YL9jeJm/
- html格式的報告:
image實戰(zhàn)中問題
-
SSLError:http://2.python-requests.org/zh_CN/latest/user/advanced.html#ssl
方法1.在參數中加入
verify=False
可以不進行安全驗證江耀,requests.get('https://github.com', verify=True)
方法2.為 verify 傳入 CA_BUNDLE 文件的路徑剩胁,或者包含可信任 CA 證書文件的文件夾路徑。
requests.get('https://github.com', verify='/path/to/certfile')
- 作業(yè)思路
- 測試用例.py
- 實例化調用被測類的方法進行測試用例編寫
- 斷言
- 異常處理
- 測試套件.py
- 存儲要運行的測試用例
- 執(zhí)行測試套件中的測試用例
- 根據測試套件.py中生成測試報告
- cookie處理
- 相當于面試題:后面的用例需要用到前面返回的某些值如何解決祥国?
- 方法1:setUp()方法
大部分請求都要帶著cookie,可以寫一個登錄的用例到`def setUp()`中昵观,每一條用例都采用登錄的cookie
```
def setUp():
response=request.get(url,data)
cookie=response.request.cookie
def add(self,url,data,cookie):
...
```
- 方法2:全局變量
```
COOKIE=None #全局變量
class TestHttp(unittest.Testcase):
def add(self):
golbal COOKIE #聲明全局變量
response=request.get(url,data)
if response.cookies: #如果response.cookies有值
COOKIE=response.cookies #給全局變量賦新值
```
缺點是關聯性太強,比如登錄失敗舌稀,其他都跪了
- 方法3:反射機制 setattr\hasattr\getattr\delattr
`setattr(類名,"屬性名","屬性值")`
```
# 示例
class GetData:
Cookie="小郭"
if __name__ == '__main__':
print(GetData.Cookie)
setattr(GetData,"Cookie","小黃")#set類中的屬性值進行修改,attr--attribute
print(GetData.Cookie)
print(hasattr(GetData,"Cookie"))#判斷是否有這個屬性
print(getattr(GetData,"Cookie"))#獲取這個屬性的值
delattr(GetData,"Cookie") #刪除這個屬性
print(hasattr(GetData,"Cookie"))
```
實戰(zhàn)應用:
```
#get_data.py文件
class GetData:
Cookie=None
```
```
#測試用例.py
from xxx import get_data
class TestHttp(unittest.Testcase):
def add(self):
golbal COOKIE #聲明全局變量
response=request.get(url,data,getattr(GetData,"Cookie"))
```
unittest總結
-
unittest原理
image -
unittest核心步驟
- testcase 一個testcase的示例就是一條測試用例
- testsuite 多個測試用例組成一個suite
- 方法一:suite.addTest("測試用例的函數名")
- 方法二:TestLoader
```
loader=unittest.TestLoader()
#該測試類中以test_開頭的用例都加載進來
suite.addTest(loader.loadTestFromTestCase(測試用例的類名))
#該模塊中以test_開頭的用例都加載進來啊犬,一個模塊可能有多個測試類,需要import該模塊
suite.addTest(loader.loadTestFromModule(模塊名))
```
- testrunner 執(zhí)行用例
```
runner=unittest.TextTestRunner()
runner.run(suite)
```
- test fixture