在之前的文章里我們已經(jīng)學(xué)習(xí)了Python自帶測試框架UnitTest,但是UnitTest具有一定的局限性
這篇文章里我們來學(xué)習(xí)第三方框架Pytest,它在保留了UnitTest框架語法的基礎(chǔ)上有著更多的優(yōu)化處理
下面我們將從以下角度來介紹Pytest:
Pytest基本介紹
Pytest基本使用
Pytest進(jìn)階內(nèi)容
Pytest基本介紹
下面我們首先來簡單介紹Pytest及相關(guān)內(nèi)容
單元測試框架
我們首先需要知道測試一般分為四個(gè)方面的測試:
單元測試:稱模塊測試,針對(duì)軟件設(shè)計(jì)中的最小單位——程序模塊,進(jìn)行正確性檢查的測試工作
集成測試:稱組裝測試,通常在單元測試的基礎(chǔ)上,將所有程序模塊進(jìn)行有序的、遞增測試,重點(diǎn)測試不同模塊的接口部分
系統(tǒng)測試:將整個(gè)軟件系統(tǒng)看成一個(gè)整體進(jìn)行測試,包括對(duì)功能、性能以及軟件所運(yùn)行的軟硬件環(huán)境進(jìn)行測試
驗(yàn)收測試:指按照項(xiàng)目任務(wù)書或合同、供需雙方約定的驗(yàn)收依據(jù)文檔進(jìn)行的對(duì)整個(gè)系統(tǒng)的測試與評(píng)審,決定是否接收或拒收系統(tǒng)
而我們這篇文章主要針對(duì)的是單元測試:
Python:通常使用UnitTest和Pytest來進(jìn)行單元測試自動(dòng)化,但Pytest已經(jīng)成為主流
Java:通常使用Testng和Junit來進(jìn)行單元測試自動(dòng)化,但Testng已經(jīng)成為主流
最后我們需要明白單元測試框架的主要功能:
發(fā)現(xiàn)測試用例
執(zhí)行測試用例
判斷測試結(jié)果
生成測試報(bào)告
框架基本介紹
下面我們來簡單介紹Pytest框架:
pytest是一個(gè)非常成熟的單元測試框架,經(jīng)過多版本的迭代,主要優(yōu)點(diǎn)在于靈活和簡單
pytest具有極強(qiáng)的兼容性和生態(tài)環(huán)境,它可以結(jié)合selenium,requests,appium完成各種不同的自動(dòng)化
pytest具有更好的頁面展示效果,它可以生成自定義allure報(bào)告以及和Jenkins持續(xù)集成
下面我們給出一些和Pytest框架可以很好聚合的框架類型:
pytestpytest-html:主要用來生成html報(bào)告的插件
pytest-xdist:主要用來進(jìn)行多線程運(yùn)行的插件
pytest-ordering:主要用來改變用例的執(zhí)行順序的插件
pytest-rerunfailres:主要用來失敗用例重跑的插件
allure-pytest:主要用來生成美觀自定義的allure報(bào)告
我們可以采用一種比較簡便的方式來一次性下載這些框架:
# 首先我們需要將這些名稱全部放入一個(gè)txt文件中,假設(shè)我們放在requestment.txt文件中 # requestment.txt文件 pytest-html pytest-xdist pytest-ordering pytest-rerunfailures # 我們只需要在pycharm的console中輸入指令下載該文件夾中全部內(nèi)容即可 pip install -r requirements.txt
Pytest基本使用
下面我們來介紹Pytest的基本使用
Pytest默認(rèn)測試用例
下面我們首先講解Pytest默認(rèn)測試用例的格式:
# 首先我們的模塊名(文件名)通常被統(tǒng)一存放在一個(gè)testcases文件夾中,然后需要保證模塊名須以test_開頭或者_(dá)test結(jié)尾 # 例如我們下面的模塊名命名就是正確示例 test_demo1 demo2_test # 然后我們需要注意我們模塊中的測試類類名必須以Test開頭,并且不能帶有init方法 # 例如我們下面的類名命名就是正確示例 class TestDemo1: class TestLogin: # 最后我們需要注意我們測試類中的測試方法名(Case名)必須以test_開頭 # 例如我們下面的模塊名命名就是正確示例 test_demo1(self) test_demo2(self) # 我們給出一個(gè)測試用例例子: # 文件名為test_demo1 class TestDemo: def test_demo1(self): print("測試用例1") def test_demo2(self): print("測試用例2") # 當(dāng)然我們上述的要求都不是必須相同的,在后續(xù)我們可以進(jìn)行修改,我們將在下述講解執(zhí)行方法時(shí)講解
然后我們?cè)賮碇v解一下Pytest的測試用例該如何執(zhí)行:
# 首先我們講解一下全局配置文件pytest.ini # 我們可以在pytest.ini中進(jìn)行一些屬性的配置來修改Pytest的默認(rèn)屬性,我們需要在項(xiàng)目的根目錄下創(chuàng)建,名稱必須是pytest.ini 1 [pytest] 2 #參數(shù) 3 addopts = ‐vs # 這里指當(dāng)默認(rèn)使用指令時(shí)的一些輔助參數(shù),我們后面會(huì)講解 4 testpaths = ./testcases# 這里指默認(rèn)的執(zhí)行路徑,它會(huì)默認(rèn)執(zhí)行該文件夾下所有的滿足條件的測試case 5 python_files = test_*.py# 這里就是前面我們所說的文件命名規(guī)則 6 python_classes = Test*# 這里就是前面我們所說的類名命名規(guī)則 7 python_functions = test_*# 這里就是前面我們所說的Case命名規(guī)則 8 #標(biāo)記 9 markers =# 這里是冒煙規(guī)則,我們后面會(huì)講到 10 smoke:冒煙用例 11 product_manage:商品管理 # 然后我們首先來講采用console命令行執(zhí)行Pytest的方法 # 最簡單的就是直接在console命令行輸入pytest,如果存在pytest.ini,它會(huì)根據(jù)文件內(nèi)容進(jìn)行執(zhí)行;如果沒有就按照默認(rèn)格式執(zhí)行 # 但是我們可以通過一些參數(shù)來強(qiáng)化pytest參數(shù)指令 # -vs: -v輸出詳細(xì)信息 -s輸出調(diào)試信息 pytest -vs # -n: 多線程運(yùn)行(前提安裝插件:pytest-xdist) pytest -vs -n=2 # --reruns num: 失敗重跑(前提安裝插件:pytest-rerunfailres) pytest -vs --reruns=2 # -x: 出現(xiàn)一個(gè)用例失敗則停止測試 pytest -vs -x # --maxfail: 出現(xiàn)幾個(gè)失敗才終止 pytest -vs --maxfail=2 # --html: 生成html的測試報(bào)告,后面 需要跟上所創(chuàng)建的文件位置及文件名稱(前提安裝插件:pytest-html) pytest -vs --html ./reports/result.html # -k: 運(yùn)行測試用例名稱中包含某個(gè)字符串的測試用例,我們可以采用or表示或者,采用and表示都 # 采用or就表示:我們的運(yùn)行用例名稱中包含or兩側(cè)的其中一個(gè)數(shù)據(jù)即可 # 采用and就表示:我們的運(yùn)行用例名稱中包含and兩側(cè)的所有數(shù)據(jù)才滿足條件 pytest -vs -k "qiuluo" pytest -vs -k "qiuluo or weiliang" pytest -vs -k "qiuluo and weiliang" # -m:冒煙用例執(zhí)行,后面需要跟一個(gè)冒煙名稱 # 我們?cè)谶@里簡單介紹一下冒煙用例的執(zhí)行方法,我們這里其實(shí)就是一個(gè)分組執(zhí)行的方法 # 例如我們的用例劃分為user_manage用戶管理測試和product_manage商品管理測試,我們只希望執(zhí)行其中一組測試 # 首先我們需要在他們的不同方法上進(jìn)行@mark劃分,具體操作如下: class TestDemo: # 我們?cè)贑ase上采用@pytest.mark. + 分組名稱,就相當(dāng)于該方法被劃分為該分組中 # 注意:一個(gè)分組可以有多個(gè)方法,一個(gè)方法也可以被劃分到多個(gè)分組中 @pytest.mark.user_manage def test_demo1(self): print("user_manage_test1") @pytest.mark.product_manage def test_demo2(self): print("product_manage_test1") @pytest.mark.user_manage @pytest.mark.product_manage def test_demo3(self): print("manage_test1") # 我們?cè)趫?zhí)行中只需要采用前面我們所說的-m + 分組名稱即可 pytest -vs -m user_manage # 這里插一句,我們?cè)谶\(yùn)行過程中可以采用拋出異常的方式來模擬測試失?。簉aise Exception() 拋出異常 # 最后我們也可以采用main方法來執(zhí)行pytest,同樣我們也可以使用參數(shù)來進(jìn)行調(diào)節(jié) if __name__ == '__main__': pytest.main() if __name__ == '__main__': pytest.main(["‐vs"])
最后我們插入一個(gè)簡單的案例跳過方法:
# pytest的跳過案例方法其實(shí)和unittest是完全相同的 # 我們只需要采用skip或skipif方法來指定參數(shù)并貼在方法上即可跳過 # @pytest.mark.skip(跳過原因) # @pytest.mark.skipif(跳過條件,跳過原因) # 我們給出一個(gè)示例 class TestDemo: workage2 = 5 workage3 = 20 @pytest.mark.skip(reason="無理由跳過") def test_demo1(self): print("我被跳過了") @pytest.mark.skipif(workage2<10,reason="工作經(jīng)驗(yàn)少于10年跳過") def test_demo2(self): print("由于經(jīng)驗(yàn)不足,我被跳過了") @pytest.mark.skipif(workage3<10,reason="工作經(jīng)驗(yàn)少于10年跳過") def test_demo3(self): print("由于經(jīng)驗(yàn)過關(guān),我被執(zhí)行了") def test_demo3(self): print("我沒有跳過條件,所以我被執(zhí)行了")
Pytest前后置方法
首先我們需要先了解前后置是什么:
前后置就是針對(duì)不同層級(jí)方法執(zhí)行前和執(zhí)行后所需要執(zhí)行的步驟進(jìn)行封裝并執(zhí)行
這個(gè)層級(jí)通常被劃分為:文件層,類層,方法層
首先我們先來介紹Pytest通過固件來實(shí)現(xiàn)前后置的方法:
# 我們通常采用前后置來做一些方法前后的操作 # 如果我們采用方法層的前后置,那么它會(huì)在每個(gè)方法執(zhí)行前后去執(zhí)行該內(nèi)容 # 如果我們采用類層的前后置,那么它會(huì)在調(diào)用這個(gè)類內(nèi)所有方法的前后去執(zhí)行該內(nèi)容,但是無論該類的方法執(zhí)行多少次,它只會(huì)調(diào)用一次 # 例如我們做login測試時(shí),我們只需要在開始測試時(shí)打開一次瀏覽器,然后在測試結(jié)束時(shí)關(guān)閉一次瀏覽器,那么我們就采用類的前后置 # 我們做login測試時(shí),為了保證前置操作不對(duì)后續(xù)Case有影響,所以我們?cè)趫?zhí)行方法前打開該網(wǎng)頁,執(zhí)行方法后關(guān)閉該網(wǎng)頁,采用方法的前后置 # Pytest的固件前后置其實(shí)和unittest是基本相同的 # 首先是方法級(jí)別的固件前后置 # 它是在每個(gè)測試方法(用例代碼) 執(zhí)行前后都會(huì)自動(dòng)調(diào)用的結(jié)構(gòu) # 方法執(zhí)行之前 def setUp(self): 每個(gè)測試方法執(zhí)行之前都會(huì)執(zhí)行 pass # 方法執(zhí)行之后 def tearDown(self): 每個(gè)測試方法執(zhí)行之后都會(huì)執(zhí)行 pass # 然后是針對(duì)類級(jí)別的固件前后置 # 它是在每個(gè)測試類中所有方法執(zhí)行前后 都會(huì)自動(dòng)調(diào)用的結(jié)構(gòu)(在整個(gè)類中執(zhí)行之前或之后執(zhí)行一次) # 需要注意:類級(jí)別的固件前后置, 是一個(gè)類方法 # 類中所有方法之前 @classmethod def setUpClass(cls): pass # 類中所有方法之后 @classmethod def tearDownClass(cls): pass # 最后是針對(duì)模塊級(jí)別的固件前后置 # 在每個(gè)代碼文件執(zhí)行前后執(zhí)行的代碼結(jié)構(gòu) # 需要注意:模塊級(jí)別的需要寫在類的外邊直接定義函數(shù)即可 # 代碼文件之前 def setUpModule(): pass # 代碼文件之后 def tearDownModule(): pass # 下面我們采用一個(gè)用戶賬戶登錄的用例來簡單展示一下固件前后置 import unittest class TestLogin(unittest.TestCase): # 在執(zhí)行該類前所需要調(diào)用的方法 @classmethod def setUpClass(cls) -> None: print('------打開瀏覽器') # 在執(zhí)行該類后所需要調(diào)用的方法 @classmethod def tearDownClass(cls) -> None: print('------關(guān)閉瀏覽器') # 每個(gè)測試方法執(zhí)行之前都會(huì)先調(diào)用的方法 def setUp(self): print('輸入網(wǎng)址......') # 每個(gè)測試方法執(zhí)行之后都會(huì)調(diào)用的方法 def tearDown(self) -> None: print('關(guān)閉當(dāng)前頁面......') # 測試Case1 def test_1(self): print('輸入正確用戶名密碼驗(yàn)證碼,點(diǎn)擊登錄 1') # 測試Case2 def test_2(self): print('輸入錯(cuò)誤用戶名密碼驗(yàn)證碼,點(diǎn)擊登錄 2')
然后我們還需要講解一下Fixtrue實(shí)現(xiàn)前后置的方法:
# 首先我們需要知道Fixtrue所實(shí)現(xiàn)的功能基本和固件所實(shí)現(xiàn)的功能是一樣的,但是會(huì)更加方便 # 首先我們給出Fixture的完整格式,然后我們?cè)俜珠_介紹各個(gè)參數(shù) @pytest.fixture(scope=None,autouse=False,params=None,ids=None ,name=None) # scope:作用范圍 # 參數(shù)主要有三種:function函數(shù),class類,package/session包 # function:在函數(shù)層面上執(zhí)行前后置 # 我們通常采用yield進(jìn)行前后置劃分,yield前是前置,yield后是后置 @pytest.fixture(scope="function") def exe_database_sql(): print("執(zhí)行SQL查詢") yield print("關(guān)閉數(shù)據(jù)庫連接") # 我們還可以通過yield或return去返回一些參數(shù)在方法中使用 # 但是需要注意,yield返回參數(shù)后后置仍舊可以執(zhí)行,但是return返回參數(shù)后后置操作無法執(zhí)行 @pytest.fixture(scope="function") def exe_database_sql(): print("執(zhí)行SQL查詢") yield "success" # return "success" 執(zhí)行后無法執(zhí)行后置操作 print("關(guān)閉數(shù)據(jù)庫連接") # 我們的方法在調(diào)用時(shí),可以直接使用exe_database_sql表示返回信息進(jìn)行輸出 def test_2(self,exe_database_sql): print(exe_database_sql) # class:在類之前和之后執(zhí)行 @pytest.fixture(scope="class") def exe_database_sql(): print("執(zhí)行SQL查詢") yield print("關(guān)閉數(shù)據(jù)庫連接") # package/session:在整個(gè)項(xiàng)目會(huì)話之前和之后執(zhí)行 @pytest.fixture(scope="session") def exe_database_sql(): print("執(zhí)行SQL查詢") yield print("關(guān)閉數(shù)據(jù)庫連接") # autouse:是否自動(dòng)啟動(dòng) # 該參數(shù)默認(rèn)為False,我們可以將其修改為True # 該參數(shù)的功能主要在判斷該固件是否在自定義范圍內(nèi)可以自動(dòng)啟動(dòng) # 若自動(dòng)啟動(dòng),則所有方法在執(zhí)行時(shí)都會(huì)自動(dòng)執(zhí)行該前后置;但若為False,則我們需要手動(dòng)啟動(dòng) # 首先如果是自動(dòng)啟動(dòng),則我們無需關(guān)心任何參數(shù),我們的所有方法都會(huì)自動(dòng)調(diào)用 @pytest.fixture(scope="function",autoues=True) def exe_database_sql(): print("執(zhí)行SQL查詢") yield print("關(guān)閉數(shù)據(jù)庫連接") # 但若是關(guān)閉自動(dòng)啟動(dòng),我們?cè)诓煌膕cope下有不同的調(diào)用方法 @pytest.fixture(scope="function",autoues=Flase) def exe_database_sql(): print("執(zhí)行SQL查詢") yield print("關(guān)閉數(shù)據(jù)庫連接") # scope = function:我們需要在方法后加上該Fixture方法名 def test_2(self,exe_database_sql): print(exe_database_sql) # scope = class:我們需要在對(duì)應(yīng)的類上添加@pytest.mark.usefixtures("exe_database_sql")裝飾器調(diào)用 @pytest.mark.usefixtures("exe_database_sql") class TestDemo: pass # scope = session:.一般會(huì)結(jié)合conftest.py文件來實(shí)現(xiàn),我們后面再介紹 # 還需要注意autouse僅限于在自己的類中使用上述方法,如果要跨類使用,那么我們也需要在conftest.py中配置 # params:實(shí)現(xiàn)參數(shù)化配置 # 通常我們的腳本都是根據(jù)導(dǎo)出的yaml文件進(jìn)行屬性填充,針對(duì)參數(shù)化我們后面再講,我們先將Fixture的參數(shù)化 # params通常后面跟上具體的數(shù)據(jù)(列表,元組等),然后我們?cè)谡{(diào)用時(shí)有固定的寫法 # 首先我們需要在Fixture方法參數(shù)中定義一個(gè)request,然后使用request.param來使用我們傳遞的params數(shù)據(jù) class TestDemo: def read_yaml(): return ["胡桃","胡桃寶寶","胡桃廚"] # 首先我們的參數(shù)需要獲取數(shù)據(jù):params=read_yaml() @pytest.fixture(scope="function",autouse=False,params=read_yaml()) # 然后我們的Fixture方法需要一個(gè)request參數(shù) def exe_database_sql(request): print("執(zhí)行SQL查詢") # 我們通過request.param獲取數(shù)據(jù),可以采用yield返回該數(shù)據(jù) yield request.param print("關(guān)閉數(shù)據(jù)庫連接") # ids:參數(shù)別名id # 不能單獨(dú)使用,必須和params一起使用,作用是對(duì)參數(shù)起別名 # 我們?cè)诓捎胮ytest進(jìn)行測試數(shù)據(jù)輸出時(shí)會(huì)有對(duì)應(yīng)的方法調(diào)用n次,該n次采用不同的params參數(shù),這個(gè)ids就是修改了console控制臺(tái)展示數(shù)據(jù) class TestDemo: def read_yaml(): return ["胡桃","胡桃寶寶","胡桃廚"] # 當(dāng)我們書寫了ids,我們的控制輸出就不會(huì)再是上面的["胡桃","胡桃寶寶","胡桃廚"],而是我們所書寫的["1","2","3"] @pytest.fixture(scope="function",autouse=False,params=read_yaml(),ids=["1","2","3"]) def exe_database_sql(request): print("執(zhí)行SQL查詢") # 我們通過request.param獲取數(shù)據(jù),可以采用yield返回該數(shù)據(jù) yield request.param print("關(guān)閉數(shù)據(jù)庫連接") # name:Fixture別名 # 作用是給fixtrue起別名,一旦使用了別名,那么fixtrue的名稱就不能再用了,只能用別名 class TestDemo: # 如果我們?cè)谶@里使用到了別名 @pytest.fixture(scope="function",name="exe_datebase_sql_name") def exe_database_sql(request): print("執(zhí)行SQL查詢") yield print("關(guān)閉數(shù)據(jù)庫連接") # 我們這里就需要使用別名進(jìn)行操作,之前的名稱無法使用 def test_2(self,exe_datebase_sql_name): print(exe_database_sql)
接下來我們就將會(huì)講解到我們剛剛提到的conftest.py文件:
# 首先我們需要知道conftest.py文件的名字是固定形式,不可改變 # conftest.py文件主要就是用來存儲(chǔ)我們的Fixture,然后我們會(huì)根據(jù)該文件的不同位置來判斷可以使用的方法 # conftest可以在不同的目錄級(jí)別下創(chuàng)建,如果我們?cè)诟夸浵聞?chuàng)建,那么所有case都會(huì)使用到該Fixture # 但是如果我們?cè)趖estcases文件夾下的某個(gè)模塊文件下創(chuàng)建conftest.py,那么它的作用范圍就只包含在該目錄下 # 根目錄創(chuàng)建的conftest.py # 我們?cè)谠撃夸浵碌腸onftest文件里寫的所有fixture可以在任意測試類下執(zhí)行 import pytest @pytest.fixture(scope="function",name="exe_datebase_sql_name") def exe_database_sql(): print("全部方法運(yùn)行前均可以執(zhí)行") yield print("全部方法運(yùn)行后均可以執(zhí)行") # testcases文件下的所有測試類 # 這里需要注意:我們使用conftest下的Fixture時(shí),不需要import導(dǎo)包就可以使用 import pytest class TestDemo1: # 測試Case1 def test_1(self,exe_datebase_sql_name): print('輸入正確用戶名密碼驗(yàn)證碼,點(diǎn)擊登錄 1' + exe_datebase_sql_name) # testcases文件夾下的usercases文件夾下創(chuàng)建的conftest.py # 我們?cè)谠撃夸浵聞?chuàng)建的conftest文件里寫的所有fixture僅可以在該目錄下的測試類中使用,在其他測試類中使用會(huì)出現(xiàn)報(bào)錯(cuò) import pytest @pytest.fixture(scope="function",name="usercases_fixture") def exe_database_sql(): print("usercases方法運(yùn)行前均可以執(zhí)行") yield print("usercases方法運(yùn)行后均可以執(zhí)行") # testcases文件下的usercases文件夾下的測試類 import pytest class TestUserCases1: # 測試Case1 def test_1(self,usercases_fixture): print('輸入正確用戶名密碼驗(yàn)證碼,點(diǎn)擊登錄 1' + usercases_fixture) # 最后我們簡單給出一個(gè)前后置執(zhí)行順序優(yōu)先級(jí): fixture_session > fixture_class > setup_class > fixture_function > setup
然后最后我們給出前后置執(zhí)行的一個(gè)總體邏輯順序:
查詢當(dāng)前目錄下的conftest.py文件
查詢當(dāng)前目錄下的pytest.ini文件并找到測試用例的位置
查詢用例目錄下的conftest.py文件
查詢測試用例的py文件中是否有setup,teardown,setup_class,teardown_class
再根據(jù)pytest.ini文件的測試用例的規(guī)則去查找用例并執(zhí)行
Pytest進(jìn)階內(nèi)容
最后我們?cè)賮碇v解一些pytest比較關(guān)鍵性的一些進(jìn)階內(nèi)容
Allure效果美化
我們?cè)谑褂肞ytest所生成的頁面往往不夠美觀且展示信息雜亂不好分析,所以我們通常搭載allure來實(shí)現(xiàn)界面美化:
Allure框架是一個(gè)靈活輕量級(jí)多語言測試報(bào)告工具
它不僅可以以WEB的方式展示簡介的測試結(jié)果,而且允許參與開發(fā)過程的每個(gè)人從日常執(zhí)行的測試中最大限度的提取有用信息
下面我們就來學(xué)習(xí)如何安裝使用allure:
# 首先我們需要去下載在電腦上下載allure并配置好環(huán)境變量 # 我們這里給出官網(wǎng)下載地址:https://github.com/allure-framework/allure2/releases # 溫馨提醒:下載鏈接在github上,如果無法打開可以刷新重試或者使用加速器梯子等輔助工具 # 環(huán)境變量的配置只需要將bin文件所在目錄放在電腦的Path路徑下即可,這里不再展示 # 第二步我們需要在pycharm上下載allure-pytest插件(如果之前pip了那個(gè)整體文件,這里應(yīng)該是已經(jīng)下載過了) pip install allure-pytest # 第三步我們就可以直接來生成allure的測試結(jié)果展示界面了 # 1.我們通常首先需要生成一個(gè)allure臨時(shí)Json文件 # 我們通常會(huì)加上這么一串"‐‐alluredir=./temps ‐‐clean‐alluredir" # ‐‐alluredir = 文件生成地址 : 表示我們將allure臨時(shí)文件生成在我們所指定的相對(duì)臨時(shí)目錄下 # ‐‐clean‐alluredir : 由于每次都會(huì)生成大量文件,所以我們會(huì)在生成前清除當(dāng)前目錄下的allure文件,保證我們數(shù)據(jù)都是最新數(shù)據(jù) # 2.我們需要依靠臨時(shí)文件來生成allure.html網(wǎng)頁 # 我們通常在main方法中執(zhí)行 if __name__ == '__main__': # 正常運(yùn)行 pytest.main() # 休眠:主要為了JSON臨時(shí)文件的生成 time.sleep(3) # allure generate 固定語句 + allure臨時(shí)JSON文件目錄 + -o 輸出指令 + allure.html生成文件目錄 + --clean 清除舊數(shù)據(jù) os.system("allure generate ./temps ‐o ./reports ‐‐clean")
Parametrize數(shù)據(jù)驅(qū)動(dòng)
我們通常會(huì)采用Parametrize注解來進(jìn)行數(shù)據(jù)驅(qū)動(dòng),下面我們來詳細(xì)講解一下:
# 格式:@pytest.mark.parametrize(參數(shù)名稱,參數(shù)值) # 意義:我們會(huì)將參數(shù)名稱作為id,然后根據(jù)參數(shù)值的個(gè)數(shù)去依次調(diào)用,存在n個(gè)參數(shù)值,我們將會(huì)調(diào)用n次case # 1.參數(shù)值為列表或元組時(shí),參數(shù)名稱可以為一個(gè) # 首先我們這里因?yàn)槭褂脝蝹€(gè)元素的列表(元組),我們的參數(shù)名可以為一個(gè) @pytest.mark.parametrize('caseinfo',['胡桃','胡桃寶寶','芙芙','芙芙寶寶']) # 在方法參數(shù)里,我們需要調(diào)用parametrize的參數(shù)名稱caseinfo,需要保證一模一樣 def test_01_get_token(self,caseinfo): # 在這里我們可以借助參數(shù)名稱caseinfo來代替列表中的元素 # 列表中存在幾個(gè),我們?cè)摲椒▽?zhí)行幾次,例如現(xiàn)在列表是四個(gè)元素,那么我們方法將會(huì)重復(fù)執(zhí)行四次并每次按順序賦值不同的元素 print("獲取統(tǒng)一接口鑒權(quán)碼:"+caseinfo) # 2.參數(shù)值為列表的多個(gè)時(shí),參數(shù)名稱可以為多個(gè) # 這里我們列表中嵌套了一個(gè)列表,如果我們是單參數(shù)名稱,那么輸出時(shí)就會(huì)將第一個(gè)列表['胡桃廚','胡桃寶寶']輸出出去 # 但是如果我們是多參數(shù)名稱,系統(tǒng)會(huì)自動(dòng)將第一個(gè)列表的元素分開賦值給arg1,arg2便于我們分開使用,個(gè)人還是比較推薦的 @pytest.mark.parametrize('arg1,arg2',[['胡桃廚','胡桃寶寶'],['芙芙廚','芙芙寶寶']]) # 注意:這里當(dāng)然也需要和參數(shù)名稱對(duì)應(yīng)?。?! def test_01_get_token(self,arg1,arg2): print("獲取統(tǒng)一接口鑒權(quán)碼:"+str(arg1)+" "+str(arg2))
我們?cè)谶M(jìn)行數(shù)據(jù)驅(qū)動(dòng)時(shí)通常會(huì)結(jié)合Yaml文件來進(jìn)行數(shù)據(jù)獲取,這里我們簡單介紹一下Yaml文件:
# yaml是一種數(shù)據(jù)格式,擴(kuò)展名可以是yaml,yml # 支持#注釋,通過縮進(jìn)表示層級(jí),區(qū)分大小寫,且yaml文件最后獲取的結(jié)果展示是一個(gè)字典列表格式 # yaml文件經(jīng)常用于書寫配置,例如Java的Spring中的配置文件,而我們也經(jīng)常采用yaml編寫自動(dòng)化測試用例 # yaml文件通常會(huì)出現(xiàn)兩種格式 # 字典格式:如果我們正常書寫yaml文件,如下就是字典模式 name: 胡桃 # 列表模式:如果我們采用yaml中的列表,那么我們?cè)趐y獲取時(shí)也將獲得列表 msjy: - name1: 胡桃 - name2: 芙芙 - ages1: 18 - ages2: 19 # 我們也可以利用這個(gè)特性,直接在yaml中做多個(gè)列表,來多次提取 - name:'xxx' age:18 - name:'xxx' age:20 # 我們這里首先給出一個(gè)解析yaml文件的示例函數(shù): import os.path import yaml # 這里是獲取當(dāng)前路徑,因?yàn)槲覀冃枰业綄?duì)應(yīng)的yaml文件,那么具體路徑就需要我們進(jìn)行拼接 def get_obj_path(): # 這里我們使用了Python的os類來進(jìn)行當(dāng)前路徑獲取,最后返回結(jié)果其實(shí)是一個(gè)String字符串 # 我們以'common'作為分界(common是當(dāng)前文件夾的名稱,我們將該Str進(jìn)行劃分,獲取前面的部分),獲取到前面的路徑部分來進(jìn)行拼接 return os.path.dirname(__file__).split('common')[0] # 然后我們這里定義一個(gè)方法來解析yaml文件 def read_yaml(yamlPath): with open(get_obj_path() + yamlPath,mode = 'r',encoding = 'utf-8') as f: # 這里需要我們pip install pyyaml value = yaml.load(steam=f,Loader=yaml.FullLoader) return value # 然后我們這里采用一個(gè)main方法來執(zhí)行上述用例(其實(shí)應(yīng)該在其他測試類中執(zhí)行) if __name__ = '__main__': # 調(diào)用read_yaml方法并給出yaml路徑 print(read_yaml('testcase/user_manage/get_token.yaml')) # 了解了所有東西之前我們就可以結(jié)合之前的Parametrize來進(jìn)行操作: # 我們這里將所需要的數(shù)據(jù)變?yōu)閞ead_yaml讀取的yaml文件內(nèi)容 @pytest.mark.parametrize('caseinfo',read_yaml('testcase/user_manage/get_token.yaml')) def test_01_get_token(self,caseinfo): # 這里我們就可以獲取到y(tǒng)aml文件內(nèi)容并輸出了 print("獲取統(tǒng)一接口鑒權(quán)碼:"+caseinfo) # 當(dāng)然如果我們了解我們的yaml中擁有什么元素,我們還可以采用[]的方式具體表達(dá)出來 @pytest.mark.parametrize('caseinfo',read_yaml('testcase/user_manage/get_token.yaml')) def test_01_get_token(self,caseinfo): print("獲取統(tǒng)一接口鑒權(quán)碼:") # 這里我們可以直接獲取namekey對(duì)應(yīng)的value print("caseinfo[name]:"+ caseinfo['name']) # 這里我們可以分別獲取request層下的method,url,data分別對(duì)應(yīng)的value print("caseinfo[name]:"+ caseinfo['request']['method']) print("caseinfo[name]:"+ caseinfo['request']['url']) print("caseinfo[name]:"+ caseinfo['request']['data'])
編輯:黃飛
-
系統(tǒng)測試
+關(guān)注
關(guān)注
2文章
35瀏覽量
14817 -
集成測試
+關(guān)注
關(guān)注
0文章
25瀏覽量
8242 -
數(shù)據(jù)庫
+關(guān)注
關(guān)注
7文章
3816瀏覽量
64458 -
python
+關(guān)注
關(guān)注
56文章
4797瀏覽量
84757
原文標(biāo)題:一篇文章帶你了解Python常用自動(dòng)化測試框架——Pytest
文章出處:【微信號(hào):magedu-Linux,微信公眾號(hào):馬哥Linux運(yùn)維】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論