HttpRunner3.X - 實現參數化驅動

一、前言

  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  https://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("https://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("https://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封裝參考https://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("https://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參數化運行結果

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章