做外貿(mào)收費(fèi)的網(wǎng)站seo交流論壇
unittest
- 學(xué)習(xí)目標(biāo)
- unittest 框架的基本使??法(組成)
- 斷?的使? (讓程序?動(dòng)的判斷預(yù)期結(jié)果和實(shí)際結(jié)果是否相符)
- 參數(shù)化(多個(gè)測試數(shù)據(jù), 測試代碼寫?份 傳參)
- ?成測試報(bào)告
- 復(fù)習(xí)python
- unittest 框架的介紹
- 核?要素(組成)
- 1. TestCase 測試?例, 這個(gè)測試?例是 unittest 的組成部分,作?是 ?來書寫真正的?例代碼(腳本)
- 2. Testsuite 測試套件, 作?是?來組裝(打包)
- 3. TestRunner 測試執(zhí)?(測試運(yùn)?), 作? 是?例執(zhí)?TestSuite(測試套件)的
- 4. TestLoader 測試加載, 是對 TestSuite(測試套件) 功能的補(bǔ)充, 作?是?來組裝(打包) TestCase(測試?例) 的
- 5. Fixture 測試夾具, 是?種代碼結(jié)構(gòu), 書寫 前置?法(執(zhí)??例之前的?法)代碼 和后置?法(執(zhí)??例之后的?法) 代碼 ,即 ?例執(zhí)?順序 前置 ---> ?例 ---> 后置
- TestCase 測試?例
- TestSuite 和 TestRunner
- TestSuite(測試套件)
- TestRunner(測試執(zhí)?)
- 整體步驟
- 代碼案例
- TestLoader 測試加載
- 練習(xí)
- TestLoader 練習(xí)
- 練習(xí) 2
- Fixture
- ?法級別 Fixture
- 類級別 Fixture
- 模塊級別Fixture(了解)
- 登錄練習(xí)
- 斷言
- 練習(xí)
- 參數(shù)化
- 使用
- 練習(xí)
- 測試報(bào)告 HTMLTestReport
- 獲取當(dāng)前路徑
- 案例
- 測試的方法
- 測試的數(shù)據(jù)
- 讀取測試數(shù)據(jù)
- 測試用例代碼
- suit報(bào)告代碼
- 跳過
學(xué)習(xí)目標(biāo)
unittest 框架的基本使??法(組成)
斷?的使? (讓程序?動(dòng)的判斷預(yù)期結(jié)果和實(shí)際結(jié)果是否相符)
參數(shù)化(多個(gè)測試數(shù)據(jù), 測試代碼寫?份 傳參)
?成測試報(bào)告
復(fù)習(xí)python
unittest 框架的介紹
什么是框架
- framework
- 為了解決?類事情的功能集合
Unittest 框架
是 Python ?帶的單元測試框架
- ?帶的, 可以直接使?, 不需要單外安裝
- 測試?員 ?來做?動(dòng)化測試, 作為?動(dòng)化測試的執(zhí)?框架,即 管理和執(zhí)??例的
核?要素(組成)
1. TestCase 測試?例, 這個(gè)測試?例是 unittest 的組成部分,作?是 ?來書寫真正的?例代碼(腳本)
2. Testsuite 測試套件, 作?是?來組裝(打包)
TestCase(測試?例) 的,即 可以將多個(gè)?例腳本?件 組裝到?起
3. TestRunner 測試執(zhí)?(測試運(yùn)?), 作? 是?例執(zhí)?TestSuite(測試套件)的
4. TestLoader 測試加載, 是對 TestSuite(測試套件) 功能的補(bǔ)充, 作?是?來組裝(打包) TestCase(測試?例) 的
5. Fixture 測試夾具, 是?種代碼結(jié)構(gòu), 書寫 前置?法(執(zhí)??例之前的?法)代碼 和后置?法(執(zhí)??例之后的?法) 代碼 ,即 ?例執(zhí)?順序 前置 —> ?例 —> 后置
TestCase 測試?例
書寫真正的?例代碼(腳本)
單獨(dú)?個(gè)測試?例 也是可以執(zhí)?
- 步驟
- 導(dǎo)包 unittest
- 定義測試類, 需要繼承 unittest.TestCase 類, 習(xí)慣性類名以 Test 開頭
- 書寫測試?法, 必須以 test 開頭
- 執(zhí)?
注意事項(xiàng)
- 代碼?件名字 要滿?標(biāo)識(shí)符的規(guī)則
- 代碼?件名 不要使?中?
"""
學(xué)習(xí) TestCase(測試用例) 的使用
"""# 1. 導(dǎo)包 unittest
import unittest# 2. 定義測試類, 只要繼承 unittest.TestCase 類, 就是 測試類
class TestDemo(unittest.TestCase):# 3. 書寫測試方法, 方法中的代碼就是真正用例代碼, 方法名必須以 test 開頭def test_method1(self):print('測試方法一')def test_method2(self):print('測試方法二')# 4. 執(zhí)行
# 4.1 在類名或者方法名后邊右鍵運(yùn)行
# 4.1.1 在類名后邊, 執(zhí)行類中的所有的測試方法
# 4.1.2 在方法名后邊, 只執(zhí)行當(dāng)前的測試方法# 4.1 在主程序使用使用 unittest.main() 來執(zhí)行,
if __name__ == '__main__':unittest.main()
TestSuite 和 TestRunner
TestSuite(測試套件)
將多條?例腳本集合在?起,就是套件, 即?來組裝?例的
1. 導(dǎo)包 unittest
2. 實(shí)例化套件對象 unittest.TestSuite()
3. 添加?例?法
TestRunner(測試執(zhí)?)
1. 導(dǎo)包 unittest
2. 實(shí)例化 執(zhí)?對象 unittest.TextTestRunner()
3. 執(zhí)?對象執(zhí)? 套件對象 執(zhí)?對象.run(套件對象)
整體步驟
1. 導(dǎo)包 unittest
2. 實(shí)例化套件對象 unittest.TestSuite()
3. 添加?例?法
3.1 套件對象.addTest(測試類名('測試?法名'))
4. 實(shí)例化 執(zhí)?對象 unittest.TextTestRunner()
5. 執(zhí)?對象執(zhí)? 套件對象 執(zhí)?對象.run(套件對象)
代碼案例
# 1. 導(dǎo)包 unittest
import unittest
# 2. 定義測試類, 只要繼承 unittest.TestCase 類, 就是測試類
class TestDemo1(unittest.TestCase):# 3. 書寫測試?法, ?法中的代碼就是真正?例代碼,?法名必須以 test 開頭def test_method1(self):print('測試?法1-1')def test_method2(self):print('測試?法1-2')
# 1. 導(dǎo)包 unittest
import unittest
from hm_02_testcase1 import TestDemo1
from hm_02_testcase2 import TestDemo2# 2. 實(shí)例化套件對象 unittest.TestSuite()
suite = unittest.TestSuite()# 3. 添加用例方法
# 3.1 套件對象.addTest(測試類名('測試方法名')) # 建議復(fù)制
suite.addTest(TestDemo1('test_method1'))
suite.addTest(TestDemo1('test_method2'))
suite.addTest(TestDemo2('test_method1'))
suite.addTest(TestDemo2('test_method2'))
# 4. 實(shí)例化 執(zhí)行對象 unittest.TextTestRunner()
runner = unittest.TextTestRunner()
# 5. 執(zhí)行對象執(zhí)行 套件對象 執(zhí)行對象.run(套件對象)
runner.run(suite)
TestLoader 測試加載
作?和 TestSuite 作??樣,組裝?例代碼, 同樣也需要使?TextTestRunner() 去執(zhí)?
10 個(gè)?例腳本 makeSuite()
import unittest
# 實(shí)例化加載對象并加載?例,得到套件對象
# suite = unittest.TestLoader().discover('?例所在的?錄', '?例代碼?件名*.py')
suite = unittest.TestLoader().discover('.','hm_02*.py')
# 實(shí)例化執(zhí)?對象并執(zhí)?
# runner = unittest.TextTestRunner()
# runner.run(suite)
unittest.TextTestRunner().run(suite)
練習(xí)
TestLoader 練習(xí)
1. 創(chuàng)建?個(gè)?錄 case, 作?就是?來存放?例腳本,
2. 在這個(gè)?錄中創(chuàng)建 5 個(gè)?例代碼?件 , test_case1.py...
3. 使? TestLoader 去執(zhí)??例將來的代碼 ?例都是單獨(dú)的?錄 中存放的
test_項(xiàng)?_模塊_功能.py
import unittestclass TestDemo(unittest.TestCase):def test_1(self):print('測試方法1')
import unittestclass TestDemo(unittest.TestCase):def test_1(self):print('測試方法2')
import unittestsuite = unittest.TestLoader().discover('case', 'test*.py')unittest.TextTestRunner().run(suite)
練習(xí) 2
1. 定義?個(gè) tools 模塊, 在這個(gè)模塊中 定義 add 的?法,可以對兩個(gè)數(shù)字求和,返回求和結(jié)果
2. 書寫?例, 對 add() 函數(shù)進(jìn)?測試
1, 1, 2
1, 2, 3
3, 4, 7
4, 5, 9
-----
之前的測試?法,直接?個(gè) print
這個(gè)案例中的 測試?法,調(diào)? add 函數(shù), 使? if 判斷,來判斷
預(yù)期結(jié)果和實(shí)際結(jié)果是否相符
預(yù)期結(jié)果 2 3 7 9
實(shí)際結(jié)果 調(diào)? add()
import unittestfrom tools import addclass TestAdd(unittest.TestCase):def test_1(self):"""1,1,2"""if 2 == add(1, 1):print(f'用例 {1}, {1}, {2}通過')else:print(f'用例 {1}, {1}, {2}不通過')def test_2(self):if 3 == add(1, 2):print(f'用例 {1}, {2}, {3}通過')else:print(f'用例 {1}, {2}, {3}不通過')def test_3(self):if 7 == add(3, 4):print(f'用例 {3}, {4}, {7}通過')else:print(f'用例 {3}, {4}, {7}不通過')def test_4(self):if 9 == add(4, 5):print(f'用例 {4}, {5}, {9}通過')else:print(f'用例 {4}, {5}, {9}不通過')
from hm_06_test_add import TestAddsuite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(TestAdd))unittest.TextTestRunner().run(suite)
Fixture
代碼結(jié)構(gòu), 在?例執(zhí)?前后會(huì)?動(dòng)執(zhí)?的代碼結(jié)構(gòu)
tpshop 登錄
1. 打開瀏覽器 (?次)
2. 打開??,點(diǎn)擊登錄 (每次)
3. 輸??戶名密碼驗(yàn)證碼1,點(diǎn)擊登錄 (每次, 測試?法)
4. 關(guān)閉?? (每次)
2. 打開??,點(diǎn)擊登錄 (每次)
3. 輸??戶名密碼驗(yàn)證碼2,點(diǎn)擊登錄 (每次, 測試?法)
4. 關(guān)閉?? (每次)
2. 打開??,點(diǎn)擊登錄 (每次)
3. 輸??戶名密碼驗(yàn)證碼3,點(diǎn)擊登錄 (每次, 測試?法)
4. 關(guān)閉?? (每次)
5. 關(guān)閉瀏覽器 (?次)
?法級別 Fixture
在每個(gè)?例執(zhí)?前后都會(huì)?動(dòng)調(diào)?, ?法名是固定的
def setUp(self): # 前置# 每個(gè)?例執(zhí)?之前都會(huì)?動(dòng)調(diào)?pass
def tearDown(self): # 后置# 每個(gè)?例執(zhí)?之后 都會(huì)?動(dòng)調(diào)?pass
# ?法前置 ?例 ?法后置
# ?法前置 ?例 ?法后置
類級別 Fixture
在類中所有的測試?法執(zhí)?前后 會(huì)?動(dòng)執(zhí)?的代碼, 只執(zhí)??次
# 類級別的 Fixture 需要寫作類?法
@classmethod
def setUpClass(cls): # 類前置pass
@classmethod
def tearDownClass(cls): # 后置pass
# 類前置 ?法前置 ?例 ?法后置 ?法前置 ?例 ?法后置類后置
模塊級別Fixture(了解)
模塊, 就是代碼?件
模塊級別 在這個(gè)代碼?件執(zhí)?前后執(zhí)??次
# 在類外部定義函數(shù)
def setUpModule():pass
def tearDownModule():pass
登錄練習(xí)
import unittestclass TestLogin(unittest.TestCase):def setUp(self) -> None:print('2. 打開網(wǎng)頁, 點(diǎn)擊登錄')def tearDown(self) -> None:print('4. 關(guān)閉網(wǎng)頁')@classmethoddef setUpClass(cls) -> None:print('1. 打開瀏覽器')@classmethoddef tearDownClass(cls) -> None:print('5. 關(guān)閉瀏覽器')def test_1(self):print('3. 輸入用戶名密碼驗(yàn)證碼1,點(diǎn)擊登錄 ')def test_2(self):print('3. 輸入用戶名密碼驗(yàn)證碼2,點(diǎn)擊登錄 ')def test_3(self):print('3. 輸入用戶名密碼驗(yàn)證碼3,點(diǎn)擊登錄 ')
斷言
使用代碼自動(dòng)的判斷預(yù)期結(jié)果和實(shí)際結(jié)果是否相符
assertEqual(預(yù)期結(jié)果,實(shí)際結(jié)果)
- 判斷預(yù)期結(jié)果和實(shí)際結(jié)果是否相等,如果相等, 用例通過,如果不相等,拋出異常, 用例不通過
assertIn(預(yù)期結(jié)果,實(shí)際結(jié)果)
- 判斷預(yù)期結(jié)果是否包含在 實(shí)際結(jié)果中, 如果存在,用例通過, 如果不存在,拋出異常,用例不通過
class TestAssert(unittest.TestCase):def test_equal_1(self):self.assertEqual(10, 10) # 用例通過def test_assert_2(self):self.assertEqual(10, 11) # 用例不通過def test_in(self):# self.assertIn('admin', '歡迎 admin 登錄') # 包含 通過# self.assertIn('admin', '歡迎 adminnnnnnnn 登錄') # 包含 通過# self.assertIn('admin', '歡迎 aaaaaadminnnnnnnn 登錄') # 包含 通過# self.assertIn('admin', '歡迎 adddddmin 登錄') # 不包含 不通過self.assertIn('admin', 'admin') # 包含 通過
from hm_02_assert import TestAssertsuite = unittest.TestSuite()suite.addTest(unittest.makeSuite(TestAssert))
unittest.TextTestRunner().run(suite)
練習(xí)
1. 定義一個(gè) tools 模塊, 在這個(gè)模塊中 定義 add 的方法,可以對兩個(gè)數(shù)字求和,返回求和結(jié)果
2. 書寫用例, 對 add() 函數(shù)進(jìn)行測試
1, 1, 2
1, 2, 3
3, 4, 7
4, 5, 9
class TestAdd(unittest.TestCase):def test_1(self):self.assertEqual(2, add(1, 1))def test_2(self):self.assertEqual(3, add(1, 2))def test_3(self):self.assertEqual(7, add(3, 4))def test_4(self):self.assertEqual(9, add(4, 5))
參數(shù)化
- 通過參數(shù)的方式來傳遞數(shù)據(jù),從而實(shí)現(xiàn)數(shù)據(jù)和腳本分離。并且可以實(shí)現(xiàn)用例的重復(fù)執(zhí)行。(在書寫用例方法的時(shí)候,測試數(shù)據(jù)使用變量代替,在執(zhí)行的時(shí)候進(jìn)行據(jù)說傳遞)
- unittest 測試框架,本身不支持參數(shù)化,但是可以通過安裝unittest擴(kuò)展插 件 parameterized 來實(shí)現(xiàn)。
環(huán)境準(zhǔn)備
因?yàn)閰?shù)化的插件 不是 unittest 自帶的,所以想要使用 需要進(jìn)行安裝
Python 中 包(插件,模塊) 的安裝,使用 pip 工具
pip install parameterized
pip install -i https://pypi.douban.com/simple/ parameterized
# 在終端(cmd)中執(zhí)行
使用
1. 導(dǎo)包 from para... import para...
2. 修改測試方法,將測試方法中的測試數(shù)據(jù)使用 變量表示
3. 組織測試數(shù)據(jù),格式 [(), (), ()], 一個(gè)元組就是一組測試數(shù)據(jù)
4. 參數(shù)化,在測試方法上方使用裝飾器 @parameterized.expand(測試數(shù)據(jù))
5. 運(yùn)行(直接 TestCase 或者 使用 suite 運(yùn)行)
import unittestfrom tools import add
from parameterized import parameterizeddata = [(1, 1, 2), (1, 2, 3), (2, 3, 5), (4, 5, 9)]class TestAdd(unittest.TestCase):@parameterized.expand(data)def test_add(self, a, b, expect):print(f'a:{a}, b:{b}, expect:{expect}')self.assertEqual(expect, add(a, b))if __name__ == '__main__':unittest.main()
練習(xí)
將測試數(shù)據(jù) 定義為 json 文件, 讀取 json 文件,完成參數(shù)化
json 文件
[[1, 1, 2],[1, 2, 3],[2, 3, 5],[4, 5, 9],[10, 20, 30]
]
讀取 json 文件
import json
from app import BASE_DIRdef build_add_data():with open('../data/add_data.json') as f:data = json.load(f) # [[], [], []] ---> [(), ()]return datadef build_add_data_1():with open('../data/add_data_1.json') as f:data_list = json.load(f) # [{}, {}, {}] ----> [(), ()]new_list = []for data in data_list: # data 字典# 字典中的值,是否都需要a = data.get('a')b = data.get('b')expect = data.get('expect')new_list.append((a, b, expect))return new_listdef build_add_data_2():with open(BASE_DIR + '/data/add_data_1.json') as f:data_list = json.load(f) # [{}, {}, {}] ----> [(), ()]new_list = []for data in data_list: # data 字典# 字典中的值,是否都需要new_list.append(tuple(data.values()))return new_listdef build_login_data():with open(BASE_DIR + '/data/login_data.json', encoding='utf-8') as f:data_list = json.load(f) # [{}, {}] ---> [()]new_list = []for data in data_list:# 字典中的 desc 不需要username = data.get('username')password = data.get('password')expect = data.get('expect')new_list.append((username, password, expect))return new_listif __name__ == '__main__':# print(build_add_data_2())print(build_login_data())
import unittestfrom common.read_data import build_add_data_2
from tools import add
from parameterized import parameterizeddata = [(1, 1, 2), (1, 2, 3), (2, 3, 5), (4, 5, 9)]class TestAdd(unittest.TestCase):# @parameterized.expand(build_add_data())# @parameterized.expand(build_add_data_1())@parameterized.expand(build_add_data_2())def test_add(self, a, b, expect):print(f'a:{a}, b:{b}, expect:{expect}')self.assertEqual(expect, add(a, b))if __name__ == '__main__':unittest.main()
測試報(bào)告 HTMLTestReport
使用第三方的報(bào)告模版,生成報(bào)告 HTMLTestReport, 本質(zhì)是 TestRunner
- 安裝
pip install -i https://pypi.douban.com/simple/ HTMLTestReport
- 使用
1. 導(dǎo)包 unittest、HTMLTestReport
2. 組裝用例(套件, loader )
3. 使用 HTMLTestReport 中的 runner 執(zhí)行套件
4. 查看報(bào)告
import unittestfrom htmltestreport import HTMLTestReport
from hm_04_pa1 import TestAdd# 套件suite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(TestAdd))# 運(yùn)行對象
# runner = HTMLTestReport(報(bào)告的文件路徑后綴.html, 報(bào)告的標(biāo)題, 其他的描述信息)
# runner = HTMLTestReport('test_add_report.html', '加法用例測試報(bào)告', 'xxx')
# runner = HTMLTestReport('./report/test_add_report.html', '加法用例測試報(bào)告', 'xxx')
runner = HTMLTestReport('report/test_add_report.html', '加法用例測試報(bào)告', 'xxx')
runner.run(suite)
使用絕對路徑
將來的項(xiàng)目是分目錄書寫的, 使用相對路徑,可能會(huì)出現(xiàn)找不到文件的情況,此時(shí)需要使用 絕對路徑
方法:
1. 在項(xiàng)目的根目錄,創(chuàng)建一個(gè) Python 文件(app.py 或者 config.py)
2. 在這個(gè)文件中 獲取項(xiàng)目的目錄,在其他代碼中使用 路徑拼接完成絕對路徑的書寫
獲取當(dāng)前路徑
import os# __file__ 特殊的變量,表示當(dāng)前代碼文件名
# path1 = os.path.abspath(__file__)
# print(path1)
# path2 = os.path.dirname(path1)
# print(path2)# BASE_DIR = os.path.dirname(os.path.abspath(__file__))
BASE_DIR = os.path.dirname(__file__)if __name__ == '__main__':print(BASE_DIR)
案例
1, 對登錄函數(shù)進(jìn)行測試, 登錄函數(shù) 定義在 tools.py 中
2, 在 case 目錄中書寫用例對login 函數(shù)進(jìn)行測試, 使用斷言
3, 將 login 函數(shù)的測試數(shù)據(jù)定義在 json 文件中,完成參數(shù)化, data 目錄中
4, 生成測試報(bào)告 report 目錄中
測試的方法
def login(username, password):if username == 'admin' and password == '123456':return '登錄成功'else:return '登錄失敗'def add(a, b):return a + b
測試的數(shù)據(jù)
[{"desc": "正確的用戶名和密碼","username": "admin","password": "123456","expect": "登錄成功"},{"desc": "錯(cuò)誤的用戶名","username": "root","password": "123456","expect": "登錄失敗"},{"desc": "錯(cuò)誤的密碼","username": "admin","password": "123123","expect": "登錄失敗"},{"desc": "錯(cuò)誤的用戶名和密碼","username": "root","password": "123123","expect": "登錄失敗"}
]
讀取測試數(shù)據(jù)
def build_login_data():with open(BASE_DIR + '/data/login_data.json', encoding='utf-8') as f:data_list = json.load(f) # [{}, {}] ---> [()]new_list = []for data in data_list:# 字典中的 desc 不需要username = data.get('username')password = data.get('password')expect = data.get('expect')new_list.append((username, password, expect))return new_list
測試用例代碼
import unittestfrom common.read_data import build_login_data
from tools import login
from parameterized import parameterizedclass TestLogin(unittest.TestCase):@parameterized.expand(build_login_data())def test_login(self, username, password, expect):print(f'username: {username}, password: {password}, expect: {expect}')self.assertEqual(expect, login(username, password))
suit報(bào)告代碼
import unittestfrom app import BASE_DIR
from case.test_login import TestLogin
from htmltestreport import HTMLTestReportsuite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(TestLogin))runner = HTMLTestReport(BASE_DIR + '/report/login_report.html', '登錄測試報(bào)告', 'V1.0')
runner.run(suite)
跳過
跳過:對于一些未完成的或者不滿足測試條件的測試函數(shù)和測試類,可以跳過執(zhí)行(簡單來說, 不想執(zhí)行的測試方法,可以
設(shè)置為跳過)
- 直接將測試函數(shù)標(biāo)記成跳過
@unittest.skip('跳過的原因')
- 根據(jù)條件判斷測試函數(shù)是否跳過
@unittest.skipIf(判斷條件, reason='原因') # 判斷條件為 True, 執(zhí)行跳過
class TestSkip(unittest.TestCase):@unittest.skip('沒什么原因,就是不想執(zhí)行')def test_1(self):print('方法一')@unittest.skipIf(version >= 30, '版本號(hào)大于等于 30, 測方法不用執(zhí)行')def test_2(self):print('方法二')def test_3(self):print('方法三')if __name__ == '__main__':unittest.main()
import unittestfrom hm_06_skip import TestSkipsuite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(TestSkip))unittest.TextTestRunner().run(suite)