原文:https://www.cnblogs.com/miki-peng/p/12501341.html
為什么要學習unittest
按照測驗階段來劃分,可以將測驗分為單元測驗、集成測驗、系統測驗和驗收測驗,單元測驗是指對軟體中的最小可測驗單元在與程式其他部分相隔離的情況下進行檢查和驗證的作業,通常指函式或者類,一般是開發完成的,
單元測驗可以將測驗作業前移,及早發現問題,降低解決問題的成本,同時單元測驗還可以保證單個模塊的功能沒有問題,為后續的集成測驗提供準備,可以減少合成后的出現的問題,
對于測驗來說,單元測驗就是執行用例,為了更好的管理用例,我們需要學習Python自帶的單元測驗框架unittest.
unittest框架及原理
unittest是python自帶的一套測驗框架,學習起來也相對容易,unittest框架最核心的概念有四個:
test case:測驗用例,unittest中提供了一個基本類TestCase,可以用來創建新的測驗用例,一個TestCase的示例就是一個測驗用例;unittest中測驗用例的方法都是以test開頭的,且執行順序會按照方法名的ASCII值排序,test fixure:測驗夾具,用于測驗用例換進的搭建和銷毀,即用例測驗前環境的大件(SetUp前置條件),測驗后環境的恢復(TearDown后置條件),比如測驗前需要登陸獲取token等就是測驗用例需要的環境,運行完成后執行下一個用例前需要還原環境,以免影響下一條用例的測驗結果,test suit:測驗套件,用來把需要一起執行的測驗用例幾種放到一塊執行,相當于一個籃子,我們一般使用TestLoader來加載測驗用例到測驗套件中,test runner:測驗運行,用來執行測驗用例的,并回傳測驗用例的執行結果,可以結合圖形或者文本介面,把回傳的測驗結果更形象的展示出來,如HTMLTestRunner.
unittest斷言
斷言是測驗用例的中很重要的一部分內容,可以用來檢查操作是否正確,比如說登入處理,成功后的頁面一定有類似于用戶名稱之類的元素,這個時候我們就可以使用斷言判斷預期結果與實際是否一致,如果吻合,就可以認為測驗用例通過,
在Python基礎中,有一個 assert斷言方法,基本使用格式為 assert 運算式,基本資訊,在unittest框架中,也提供了一個自帶的斷言方式,如果斷言失敗即不通過就會拋出一個 AssertionError斷言錯誤;成功則標識通過,
以下的斷言方法都有一個 msg=None引數(表中只列出了第一個,其實都有),默認回傳 None,但是如果指定msg引數的值,則將該資訊作為失敗的錯誤資訊回傳,
| 方法 | 檢查 |
|---|---|
| assertEqual(a, b ,msg=None) | a == b |
| assertNotEqual(a, b) | a != b |
| assertTrue(x) | bool(x) is True |
| assertFalse(x) | bool(x) is False |
| assertIs(x, b) | a is b |
| assertIsNot(a, b) | a is not b |
| assertIsNone(x) | x is None |
| assertIsNotNone(x) | x is not None |
| assertIn(a, b) | a in b |
| assertNotIn(a, b) | a not in b |
| assertIsInstance(a, b) | isinstance(a, b) |
| assertNotIsInstance(a, b) | not isinstance(a, b) |
TestCase測驗用例
撰寫測驗用例前,我們需要創建一個類繼承unittest里面的TestCase類,之后我們才能真正的使用unittest框架去撰寫測驗用例.
步驟如下:
- 匯入
unittest模塊 - 創建一個測驗類,繼承
unittest.TestCase類 - 定義測驗方法,方法名必須以
test_開頭 - 呼叫unittest.main()方法來運行測驗用例,
unittest.main()方法會搜索該模塊下所有以test開頭的測驗用例和方法,并自動執行,
代碼示例
# 注冊功能代碼
# users串列存盤成功注冊的用戶
users = [{'username': 'testing', 'password': '123456'}]
def register(username, password1, password2):
if not all([username, password1, password2]):
return {'code': 0, 'msg': '所有引數不能為空.'}
# 注冊
for user in users:
if username == user['username']:
return {'code': 0, 'msg': '用戶名已存在!'}
else:
if password1 != password2:
return {'code': 0, 'msg': '兩次密碼輸入不一致!'}
else:
if 6 <= len(username) <= 18 and 6 <= len(password1) <= 18:
# 追加到users串列
users.append({'username': username, 'password': password2})
return {'code': 0, 'msg': '注冊成功.'}
else:
return {'code': 0, 'msg': '用戶名和密碼的長度必須在6~18位之間.'}
import unittest
from demo import register # 匯入被測驗代碼
class RegisterTest(unittest.TestCase):
'''注冊介面測驗類'''
def test_register_success(self):
'''注冊成功'''
data = https://www.cnblogs.com/palien/p/('palien', 'palien', 'palien') # 測驗資料
result = register(*data) # 測驗結果
expected = {'code': 0, 'msg': '注冊成功.'} # 預期結果
self.assertEqual(result, expected) # 斷言測驗結果與預期結果一致
# pass
def test_username_exist(self):
'''注冊失敗-用戶名已存在'''
data = https://www.cnblogs.com/palien/p/('testing', '123456', '123456')
result = register(*data)
expected = {'code': 0, 'msg': '用戶名已存在!'}
self.assertEqual(result, expected)
def test_username_isnull(self):
'''注冊失敗-用戶名為空'''
data = https://www.cnblogs.com/palien/p/('', 'palien', 'palien')
result = register(*data)
expected = {'code': 0, 'msg': '所有引數不能為空.'}
self.assertEqual(result, expected)
# pass
def test_username_lt18(self):
'''注冊失敗-用戶名長度大于18位'''
data = https://www.cnblogs.com/palien/p/('palienpalienpalienpalien', 'palien', 'palien')
result = register(*data)
expected = {'code': 0, 'msg': '用戶名和密碼的長度必須在6~18位之間.'}
self.assertEqual(result, expected)
# pass
def test_password1_not_password2(self):
'''注冊失敗-兩次輸入密碼不一致'''
data = https://www.cnblogs.com/palien/p/('palien', 'palien1', 'palien2')
result = register(*data)
expected = {'code': 0, 'msg': '兩次密碼輸入不一致!'}
self.assertEqual(result, expected)
# pass
# 如果要直接運行這個測驗類,需要使用unittest中的main函式來執行測驗用例
if __name__ == '__main__':
unittest.main()
# Output
Windows PowerShell
著作權所有 (C) Microsoft Corporation,保留所有權利,
嘗試新的跨平臺 PowerShell https://aka.ms/pscore6
PS D:\d_02_study\01_git> cd d:/d_02_study/01_git/papers/system/02automation
PS D:\d_02_study\01_git\papers\system\02automation> & C:/Users/TDH/AppData/Local/Programs/Python/Python310-32/python.exe d:/d_02_study/01_git/papers/system/02automation/demo.py
.....
----------------------------------------------------------------------
Ran 5 tests in 0.001s
OK
PS D:\d_02_study\01_git\papers\system\02automation>
TestFixture測驗夾具
unittest的測驗夾具有兩種使用方式,一種是以測驗用例的方法為維度的:setUp()和 tearDown();另一種是以測驗類為維度的:setUpClass()和 tearDownClass(),
代碼示例:
# users串列存盤成功注冊的用戶
users = [{'username': 'testing', 'password': '123456'}]
def register(username, password1, password2):
if not all([username, password1, password2]):
return {'code': 0, 'msg': '所有引數不能為空.'}
# 注冊
for user in users:
if username == user['username']:
return {'code': 0, 'msg': '用戶名已存在!'}
else:
if password1 != password2:
return {'code': 0, 'msg': '兩次密碼輸入不一致!'}
else:
if 6 <= len(username) <= 18 and 6 <= len(password1) <= 18:
# 追加到users串列
users.append({'username': username, 'password': password2})
return {'code': 0, 'msg': '注冊成功.'}
else:
return {'code': 0, 'msg': '用戶名和密碼的長度必須在6~18位之間.'}
import unittest
from demo import register # 匯入被測驗代碼
class RegisterTest(unittest.TestCase):
'''注冊介面測驗類'''
@classmethod # 指明這是個類方法,以類為維度去執行的
def setUpClass(cls) -> None:
'''整個測驗用例類中的用例執行之前,會先執行此方法'''
print('-----setup---class-----')
@classmethod
def tearDownClass(cls) -> None:
'''整個測驗用例類中的用例執行完成后,會執行此方法'''
print('-----teardown---class-----')
def setUp(self):
'''每條測驗用例執行前都會執行'''
print('用例{}開始執行...'.format(self))
def tearDown(self):
'''每條測驗用例執行結束后都會執行'''
print('用例{}執行結束...'.format(self))
def test_register_success(self):
'''注冊成功'''
data = https://www.cnblogs.com/palien/p/('palien', 'palien', 'palien') # 測驗資料
result = register(*data) # 測驗結果
expected = {'code': 0, 'msg': '注冊成功.'} # 預期結果
self.assertEqual(result, expected) # 斷言測驗結果與預期結果一致
# pass
def test_username_exist(self):
'''注冊失敗-用戶名已存在'''
data = https://www.cnblogs.com/palien/p/('testing', '123456', '123456')
result = register(*data)
expected = {'code': 0, 'msg': '用戶名已存在!'}
self.assertEqual(result, expected)
def test_username_isnull(self):
'''注冊失敗-用戶名為空'''
data = https://www.cnblogs.com/palien/p/('', 'palien', 'palien')
result = register(*data)
expected = {'code': 0, 'msg': '所有引數不能為空.'}
self.assertEqual(result, expected)
# pass
def test_username_lt18(self):
'''注冊失敗-用戶名長度大于18位'''
data = https://www.cnblogs.com/palien/p/('palienpalienpalienpalien', 'palien', 'palien')
result = register(*data)
expected = {'code': 0, 'msg': '用戶名和密碼的長度必須在6~18位之間.'}
self.assertEqual(result, expected)
# pass
def test_password1_not_password2(self):
'''注冊失敗-兩次輸入密碼不一致'''
data = https://www.cnblogs.com/palien/p/('palien', 'palien1', 'palien2')
result = register(*data)
expected = {'code': 0, 'msg': '兩次密碼輸入不一致!'}
self.assertEqual(result, expected)
# pass
# 如果要直接運行這個測驗類,需要使用unittest中的main函式來執行測驗用例
if __name__ == '__main__':
unittest.main()
### Output
PS D:\d_02_study\01_git> cd d:/d_02_study/01_git/papers/system/02automation
PS D:\d_02_study\01_git\papers\system\02automation> & C:/Users/TDH/AppData/Local/Programs/Python/Python310-32/python.exe d:/d_02_study/01_git/papers/system/02automation/demo.py
-----setup---class-----
用例test_password1_not_password2 (__main__.RegisterTest)開始執行...
用例test_password1_not_password2 (__main__.RegisterTest)執行結束...
.用例test_register_success (__main__.RegisterTest)開始執行...
用例test_register_success (__main__.RegisterTest)執行結束...
.用例test_username_exist (__main__.RegisterTest)開始執行...
用例test_username_exist (__main__.RegisterTest)執行結束...
.用例test_username_isnull (__main__.RegisterTest)開始執行...
用例test_username_isnull (__main__.RegisterTest)執行結束...
.用例test_username_lt18 (__main__.RegisterTest)開始執行...
用例test_username_lt18 (__main__.RegisterTest)執行結束...
.-----teardown---class-----
----------------------------------------------------------------------
Ran 5 tests in 0.004s
OK
PS D:\d_02_study\01_git\papers\system\02automation>
TestSuit測驗套件
unittest.TestSuit()類用來表示一個測驗用例集,把需要執行的用例類或模塊集合在一起,
常用的方法:
- unittest.TestSuit()
addTest():添加單個測驗用例方法addTest([...]):添加多個測驗用例方法,方法名存在一個串列
- unittest.TestLoader()
loadTestsFromTestCase(測驗類名):添加一個測驗類loadTestsFromMdule(模塊名):添加一個模塊discover(測驗用例所在的目錄):指定目錄去加載,會自動尋找這個目錄下所有符合命名規則的測驗用例
代碼示例:
'''
以下三個檔案必須在同一檔案夾下:
demo.py
test_demo.py
run_test.py
'''
import os
import unittest
import test_demo
# 第一步,創建一個測驗套件
suit = unittest.TestSuite()
# 第二步,將測驗用例加載到測驗套件中
# # 方式一,添加單條測驗用例
# case = test_demo.RegisterTest('test_register_success')
# '''
# 創建一個用例物件,
# 注意:通過用例類去創建測驗用例物件的時候,需要傳入用例的方法名(字串型別)
# 這里不是像呼叫普通類中的方法那樣通過類名.方法名呼叫,可以理解為unittest框架的特殊之處
# '''
# suit.addTest(case) # 添加用例到測驗套件中
# # 方式二:添加多條用例
# case1 = test_demo.RegisterTest('test_username_exist')
# case2 = test_demo.RegisterTest('test_username_isnull')
# suit.addTest([case1, case2]) # 添加用例到測驗套件中,注意這里使用的是suit.addTest()方法而不是suit.addTests()方法
# # 方式三:添加一個測驗用例集
# loader = unittest.TestLoader() # 創建一個加載物件
# suit.addTest(loader.loadFromTestCase(test_demo.RegisterTest)) # 通過加載物件從測驗類中加載用例到測驗套件中
# '''
# 通產我們使用方式4、5比較多,可以根據實際情況來運用,
# 其中方式5還可以自定義匹配規則,默認是會尋找目錄下的test*.py檔案,即所有以test開頭命名的py檔案,
# '''
# # 方式四:添加一個模塊(其實就是一個后綴名為.py檔案,這里就是test_demo.py檔案)
# loader = unittest.TestLoader() # 創建一個加載物件
# suit.addTest(loader.loadTestsFromModule(test_demo)) # 通過加載物件從模塊中加載測驗用例到測驗套件中
# 方式五:指定測驗用例的所在目錄路徑,進行加載
loader = unittest.TestLoader() # 創建一個加載物件
case_path = os.path.dirname(os.path.abspath(__file__)) # 檔案路徑
# print('用例所在的目錄路徑為:', case_path)
# suit.addTest(loader.discover(case_path)) # 通過加載物件從用例所在目錄加載測驗用例到測驗套件
suit.addTest(loader.discover(start_dir=case_path, pattern='test_demo*.py')) # 兩個引數:路徑和匹配規則
TestRunner執行用例
testRunner用來執行用例,并且可以生成相應的測驗報告,測驗報告有兩種形式:一種是 text文本;一種是 html格式,
html格式是 HTMLTestRunner插件輔助生成的,是Python標準庫的unittest框架的一個拓展,可以生成一個清晰直觀的html測驗報告,使用的前提就是需要下載 HTMLTestRunner.py,下載完成后放在python安裝目錄下的scripts目錄下即可,
text文本相對于html來說過于簡陋,與輸出控制臺沒有什么區別,也幾乎不適用,
代碼示例:
# demo.py,與test_demo.py和run_test.py在同一目錄下
# 匯入模塊
import unittest
import os
import test_demo
from HTMLTestReportCN import HTMLTestRunner
# 用例檔案所在目錄
base_path = os.path.dirname(os.path.abspath(__file__))
# report_path = base_path + 'report.html'
# 打開報告檔案
# 創建測驗套件
suit = unittest.TestSuite()
# 通過模塊加載測驗用例
loader = unittest.TestLoader()
suit.addTest(loader.discover(start_dir=base_path, pattern='test_demo*.py'))
# 創建測驗運行程式啟動器
runner = HTMLTestRunner(
stream=open('report.html', 'w', encoding='utf-8'), # 打開一個報告檔案,并將句柄傳給stream
tester='palien', # 報告中顯示的測驗人員
description='注冊介面測驗報告', # 報告中顯示的描述資訊
title='自動化測驗報告' # 測驗報告標題
)
# 使用啟動器去執行測驗套件里面的測驗用例
runner.run(suit)
相關引數說明:
stream:指定輸出方式tester:報告中要顯示的測驗人員的名字description:報告中要顯示的描述資訊title:測驗報告的標題verbosity:表示測驗報告資訊的詳細程度,一共三個值,默認為20(靜默模式):只能獲得總的測驗用例書和總的結果,如:總共100個,失敗901(默認模式):類似靜默模式,只是在在每個成功的用例面前有個. 每個失敗的用例前面有個F2(詳細模式):測驗結果會顯示每個測驗用例的所有相關資訊
運行完畢,在專案目錄下面會生成一個report.html檔案,在瀏覽器中打開,就可以看到測驗報告了,

問題記錄
在學習的程序中遇到了一些問題,記錄一下,
HTMLTestRunner下載
我翻了好久的博客,終于找到了一篇可用的:https://copyfuture.com/blogs-details/202112102109216096
經驗證,以下兩個檔案就支持生成上面截圖的報告,

- 報錯
TypeError: a bytes-like object is required, not 'str'解決
這是打開檔案的方式不對造成的,附上問題解決博客:https://blog.csdn.net/Teresa_lqs/article/details/126250505?spm=1001.2101.3001.6661.1&utm_medium=distribute.pc_relevant_t0.none-task-blog-2~default~CTRLIST~Rate-1-126250505-blog-116235034.pc_relevant_default&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-2~default~CTRLIST~Rate-1-126250505-blog-116235034.pc_relevant_default&utm_relevant_index=1
- 中文報告亂碼問題
問題如圖:

這是檔案編碼問題,附上問題解決博客:https://zhuanlan.zhihu.com/p/547236404
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/538030.html
標籤:其他
上一篇:O-MVLL代碼混淆方式
