HttpRunner3.X – 實現參數化驅動
- 2021 年 10 月 24 日
- 筆記
- HttpRunner測試框架
一、前言
HttpRunner3.X支援三種方式的參數化,參數名稱的定義分為兩種情況:
- 獨立參數單獨進行定義;
- 多個參數具有關聯性的參數需要將其定義在一起,採用短橫線(-)進行連接。
數據源指定支援三種方式:
- 列表:[“張三”, “李四”, “王五”] —— 這種屬於直接指定參數列表,該種方式最為簡單易用,適合參數列表比較小的情況
- debugtalk.py的回調,${get_styleCode()} —— 調用 debugtalk.py 中自定義的函數生成參數列表:該種方式最為靈活,可通過自定義 Python 函數實現任意場景的數據驅動機制,當需要動態生成參數列表時也需要選擇該種方式
- Parameterize類的回調,例如csv:${parameterize(account.csv)} ——註:這種適合數據量比較大的情況,後面會換一種方式實現
假如測試用例中定義了多個參數,那麼測試用例在運行時會對參數進行笛卡爾積組合,覆蓋所有參數組合情況。
如果使用過pytest的參數化的小夥伴一定不會陌生,@pytest.mark.parametrize()會先將param作為一個動態參數,傳遞給param,然後由httprunner在進行參數化,httprunner在pytest的parametrize上封裝了一層,增加了csv及debugtalk.py參數化的支援。
二、源碼介紹Parameters 中的使用方法
def parse_parameters(parameters: Dict,) -> List[Dict]: """ parse parameters and generate cartesian product. Args: parameters (Dict) parameters: parameter name and value mapping parameter value may be in three types: (1) data list, e.g. ["iOS/10.1", "iOS/10.2", "iOS/10.3"] (2) call built-in parameterize function, "${parameterize(account.csv)}" (3) call custom function in debugtalk.py, "${gen_app_version()}" Returns: list: cartesian product list Examples: >>> parameters = { "user_agent": ["iOS/10.1", "iOS/10.2", "iOS/10.3"], "username-password": "${parameterize(account.csv)}", "app_version": "${gen_app_version()}", } >>> parse_parameters(parameters) """ parsed_parameters_list: List[List[Dict]] = []
三、實例講解
1、前置工作
1)httprunner3.x中的參數化需要引入pytest和處理參數化的函數
import pytest from httprunner import Parameters
2)選取某個查詢介面作為例子
POST //xxx.mand/contract/page
{
"styleCode": "",
"purchaserNameLike": "",
"status": "",
"pageNum": 1,
"pageSize": 20,
}
2、第一種列表:笛卡爾積組合
2個入參進行了參數化,以下示例,運行後得到的用例執行次數是2*3,如圖1所示,
# NOTE: Generated By HttpRunner v3.1.5 # FROM: har\search.har # 參數化驅動 import self as self from httprunner import HttpRunner, Config, Step, RunRequest, RunTestCase,Parameters import pytest from config.ExcelUtiltest import ParseExcel class TestCaseSearch(HttpRunner): @pytest.mark.parametrize("param", Parameters({"styleCode": ['S21001061', 'S21000597'],"purchaserNameLike":['測試','南京公司','測試2']})) def test_start(self, param): super().test_start(param) config = Config("參數化搜索").verify(False) teststeps = [ Step( RunRequest("搜索介面") .post("//xxx.mand/web/v1/contract/page") .with_headers( **{ "Connection": "keep-alive", "Content-Length": "249", } ) .with_json( { "styleCode": "$styleCode", "purchaserNameLike": "$purchaserNameLike", "status": "", "pageNum": 1, "pageSize": 20, } ) .validate() .assert_equal("status_code", 200) .assert_equal('headers."Content-Type"', "application/json") .assert_equal("body.successful", True) .assert_equal("body.code", "200") .assert_equal("body.message", "請求成功") ), ] if __name__ == "__main__": TestCaseSearch().test_start()
圖1:笛卡爾積組合 即n*m
3、第二種debugtalk.py的回調函數
在debugtalk.py中定義一個函數,返回列表
def get_styleCode(): return [ {'styleCode':'S21001217'}, {'styleCode': 'S21001211'}, ]
在searchdriver_test.py文件調用,運行後的結果如圖2所示,
# NOTE: Generated By HttpRunner v3.1.5 # FROM: har\search.har # 參數化驅動 import self as self from httprunner import HttpRunner, Config, Step, RunRequest, RunTestCase,Parameters import pytest from config.ExcelUtiltest import ParseExcel class TestCaseSearch(HttpRunner): @pytest.mark.parametrize("param",Parameters({'styleCode':'${get_styleCode()}'})) def test_start(self, param): super().test_start(param) config = Config("參數化搜索").verify(False) teststeps = [ Step( RunRequest("搜索介面") .post("//xxx.mand/web/v1/contract/page") .with_headers( **{ "Connection": "keep-alive", "Content-Length": "249", } ) .with_json( { "styleCode": "$styleCode", "purchaserNameLike": "", "status": "", "pageNum": 1, "pageSize": 20, } ) .validate() .assert_equal("status_code", 200) .assert_equal('headers."Content-Type"', "application/json") .assert_equal("body.successful", True) .assert_equal("body.code", "200") .assert_equal("body.message", "請求成功") ), ] if __name__ == "__main__": TestCaseSearch().test_start()
圖2:調用debugtalk
4、第三種excel文件作為參數化輸入
1)根據網上查的資料,httprunner3.x可以用.csv作為數據源,寫法如下,.csv如圖3所示,
csv的路徑要使用相對路徑,不支援絕對路徑不支援\\符號的路徑,csv映射的時候,參數名要以「-」分割,name和pwd使用的-進行分割
疑問點:我在用這種方式時,會提示參數類型不正確,想不明白為什麼別人可以運行成功呢,哈哈哈
@pytest.mark.parametrize("param",Parameters({"styleCode-purchaserNameLike": "${parameterize(testdata\styleCode.csv)}"})) def test_start(self, param): super().test_start(param)
圖3:.csv文件
2)踩了坑後,經過別人的指點下(這個裝飾器只接收list類型的),所以決定寫個讀取excel的方法,並轉換成list,然後用例直接調用即可
在config文件下新建ExcelUtiltest.py(excel封裝參考//www.cnblogs.com/du-hong/p/10892379.html)
#封裝解析excel的方法 from openpyxl import load_workbook class ParseExcel: def __init__(self,excelPath,sheetName): # 將要讀取excel載入到記憶體 self.wb=load_workbook(excelPath) # 通過工作表名獲取一個工作表對象 #self.sheet=self.wb.get_sheet_by_name(sheetName) self.sheet = self.wb[sheetName] # 獲取工作表中存在數據的區域最大行號 self.maxRowNum=self.sheet.max_row def getDatasFromSheet(self): # 存放從表中取出的數據 datalist=[] for line in list(self.sheet.rows)[1:]: # 遍歷工作表中數據區域每一行 tmplist=[] tmplist.append(line[1].value) tmplist.append(line[2].value) datalist.append(tmplist) print(datalist) return datalist '''if __name__ == '__main__': #excelPath = 'E:\\03UI test\\UnittestProject\\TestData\\search_data_list.xlsx' excelPath = 'E:\\05\\api_test\\testdata\\styleCode.xlsx' sheetName=u'Sheet1' pe = ParseExcel(excelPath, sheetName) for i in pe.getDatasFromSheet(): print(i[0],i[1])'''
在用例文件searchdriver_test.py進行調用(這裡直接用Parameters,如有多個參數,用橫杠-),excel文件如圖4所示,運行結果如圖5所示
# NOTE: Generated By HttpRunner v3.1.5 # FROM: har\search.har # 參數化驅動 import self as self from httprunner import HttpRunner, Config, Step, RunRequest, RunTestCase,Parameters import pytest from config.ExcelUtiltest import ParseExcel class TestCaseSearch(HttpRunner): data = ParseExcel('E:\\05\\api_test\\testdata\\styleCode.xlsx','Sheet1') datalist = data.getDatasFromSheet() #下面是為了方便理解,直接指定的list數據 #@pytest.mark.parametrize('param',Parameters({'styleCode-purchaserNameLike':[['S21001170','南京公司'],['S21001213','南京公司']]}),) @pytest.mark.parametrize('param', Parameters({'styleCode-purchaserNameLike': datalist}), ) def test_start(self, param): super().test_start(param) config = Config("參數化搜索").verify(False) teststeps = [ Step( RunRequest("查詢介面") .post("//xxx.mand/web/v1/contract/page") .with_headers( **{ "Connection": "keep-alive", } ) .with_json( { "styleCode": "$styleCode", "purchaserNameLike": "$purchaserNameLike", "status": "", "pageNum": 1, "pageSize": 20, } ) .validate() .assert_equal("status_code", 200) .assert_equal('headers."Content-Type"', "application/json") .assert_equal("body.successful", True) .assert_equal("body.code", "200") .assert_equal("body.message", "請求成功") ), ] if __name__ == "__main__": TestCaseSearch().test_start()
圖4:excel文件數據
圖5:excel參數化運行結果