2、HttpRunner_測試用例和hook機(jī)制

PS.本系列的內(nèi)容主要來自HttpRunner官方文檔,因?yàn)閭€(gè)人習(xí)慣,在學(xué)習(xí)的時(shí)候會寫筆記用以加深記憶(cv大法),所以有本系列的筆記。
https://cn.httprunner.org/


測試用例結(jié)構(gòu)

一、概念
  • 測試用例集/testsuite:對應(yīng)一個(gè)包含單個(gè)或多個(gè)測試用例文件的文件夾(測試用例可以是json、yaml)
  • 測試用例/testcase:對應(yīng)一個(gè)包含單個(gè)或多個(gè)測試步驟的文件(文件可以是json、yaml)
  • 測試步驟/teststep:對應(yīng)測試用例文件中的一個(gè)test,其中描述單個(gè)接口測試的全部內(nèi)容:包括請求內(nèi)容、解析響應(yīng)結(jié)果、校驗(yàn)結(jié)果等

PS.在單個(gè)測試用例,它的數(shù)據(jù)存儲結(jié)構(gòu)是list of dict的形式,里面可能包含一個(gè)全局配置項(xiàng)config和若干個(gè)測試步驟test

二、變量空間作用域/context作用域

在一個(gè)測試用例中,劃分了兩層變量空間作用域:

  • config:整個(gè)測試用例的全局配置項(xiàng),作用域?yàn)樗诘臏y試用例
  • test:對應(yīng)的是測試步驟,運(yùn)行時(shí)從前到后,依次執(zhí)行各個(gè)測試步驟
    1.測試步驟中的變量空間,會繼承或覆蓋config中定義的內(nèi)容
    2.如果變量在config定義了,在test中卻沒有定義,那么該test會繼承config所定義的變量值
    3.如果變量在configtest中都定義了,那么當(dāng)前test會使用自己所定義的變量值
  • 各個(gè)test的變量空間是相互獨(dú)立,互不影響的
  • 如果需要在多個(gè)test中傳遞參數(shù)值,就需要用到extract關(guān)鍵字,并且只能從前往后進(jìn)行傳遞(解決了數(shù)據(jù)依賴問題)
三、全局變量config的字段介紹
key 必需? 類型 介紹
name string 測試用例的名稱,會在測試報(bào)告中作為標(biāo)題顯示
variables list / dict 定義的全局變量,作用域是當(dāng)前測試用例
parameters list / dict q全局參數(shù),作用域是當(dāng)前測試用例,用于實(shí)現(xiàn)數(shù)據(jù)化驅(qū)動
request dict request的公共參數(shù),作用域是當(dāng)前測試用例,常用參數(shù)有base_url、headers

官方例子(json):

"config": {
    "name": "testcase description",
    "parameters": [
        {"user_agent": ["iOS/10.1", "iOS/10.2", "iOS/10.3"]},
        {"app_version": "${P(app_version.csv)}"},
        {"os_platform": "${get_os_platform()}"}
    ],
    "variables": [
        {"user_agent": "iOS/10.3"},
        {"device_sn": "${gen_random_string(15)}"},
        {"os_platform": "ios"}
    ],
    "request": {
        "base_url": "http://127.0.0.1:5000",
        "headers": {
            "Content-Type": "application/json",
            "device_sn": "$device_sn"
        }
    },
    "output": [
        "token"
    ]
}
四、測試步驟test的字段介紹
Key 必需? 類型 備注
name string 測試步驟的名稱,會在測試報(bào)告中座位測試步驟的名稱顯示
request dict http請求的詳細(xì)內(nèi)容,具體參數(shù)可見python.request
variables list / dict 變量,作用域?yàn)樗?code>test
extract list 從當(dāng)前請求的響應(yīng)結(jié)果中提取參數(shù),并保存在參數(shù)變量中(比如token),在后續(xù)測試用例就可以通$變量(比如$token)進(jìn)行引用
validate list 結(jié)果校驗(yàn)項(xiàng),對當(dāng)前請求的響應(yīng)結(jié)果進(jìn)行判斷,作為當(dāng)前測試用例是否通過的依據(jù)
setup_hooks list 在發(fā)送請求之前先執(zhí)行hook函數(shù),主要用于準(zhǔn)備工作
teardown_hooks list 在發(fā)送請求值后執(zhí)行hook函數(shù),主要用于測試完畢后的清理工作
api str 引用接口定義,填寫對應(yīng)接口定義文件的絕對路徑或相對路徑,推薦使用相對路徑,根路徑是 debugtalk.py所在的目錄路徑。
testcase str 引用其它測試用例,填寫測試用例的絕對路徑或相對路徑,推薦使用相對路徑,根路徑是debugtalk.py所在的目錄路徑。
output str / 其他? 當(dāng)前測試步驟輸出的值,比如輸出token:output: - session_token
1.extract

根據(jù)響應(yīng)結(jié)果的數(shù)據(jù)結(jié)果,再采用不同的提取方式:

  • 響應(yīng)結(jié)果為json結(jié)構(gòu),則采用.來表示層級關(guān)系,比如說headers.Content-Type
  • 響應(yīng)結(jié)果為text/html結(jié)構(gòu),則采用正則表達(dá)式來提取
  • 詳情見:ApiTestEngine
2.validate

支持下面兩種格式(yaml):

# 1
- 判斷規(guī)則:"需判斷的屬性key","預(yù)期中的屬性value"
# 2
-{check:"需判斷的屬性key", comparator:"判斷規(guī)則", expect:"預(yù)期中的屬性value"}
  • 判斷規(guī)則/compatator
    1.eq/equals/==/is:等于
    2.lt/less_than:小于
    3.le/less_than_or_equals:小于等于
    4.gt/greater_than:大于
    5.ge/greater_than_or_equals:大于等于
    6.str_eq/string_equals:字符串相等
    7.len_eq/count_eq/length_equals:長度等于
    8.len_gt/length_greater_than:長度大于
    9.len_ge/length_greater_than_or_equals:長度大于等于
    10.len_lt:長度小于
    11.len_le:長度小于等于
    12.contains:包含
    13.ne/not_equals:結(jié)果不相同
    14.type_match:類型不相等
    15.startswith:以xx開頭
    16endswith:以xx結(jié)尾
3.預(yù)期結(jié)果/expect

顧名思義,填寫預(yù)期結(jié)果即可。是json層級關(guān)系,比如說請求的響應(yīng)內(nèi)容中code的值是0,那么“需判斷的屬性key是”content.code,“預(yù)期中的屬性value”是:0

五、hooks/鉤子

HttpRunner的鉤子機(jī)制分為兩個(gè)層面:

  • 測試用例層面/testcase
  • 測試步驟層面/teststep
1.測試用例層面/testcase

在測試用例的config中提供了setup_hooksteardown_hooks這兩個(gè)關(guān)鍵字

  • setup_hooks:在整個(gè)測試用例開始執(zhí)行前,先執(zhí)行setup_hooks所指定的函數(shù),用于測試開始前的準(zhǔn)備工作
  • teardown_hooks:在整個(gè)測試用例結(jié)束之后,再執(zhí)行teardown_hooks所指定的函數(shù),用于測試結(jié)束后的清理工作
- config:
    name: basic test with httpbin
    request:
        base_url: http://127.0.0.1:3458/
    setup_hooks:
        - ${hook_print(setup)}
    teardown_hooks:
        - ${hook_print(teardown)}
2.測試步驟層面/teststep

同樣的,在測試步驟的test中提供了setup_hooksteardown_hooks這兩個(gè)關(guān)鍵字

  • setup_hooks:在當(dāng)前測試步驟開始執(zhí)行前,先執(zhí)行setup_hooks所指定的函數(shù),用于準(zhǔn)備工作;也可以實(shí)現(xiàn)對請求的request內(nèi)容進(jìn)行預(yù)處理(比如添加一些請求頭之類的)
  • teardown_hooks:在當(dāng)前測試步驟結(jié)束之后,再執(zhí)行teardown_hooks所指定的函數(shù),用于清理工作;也可以實(shí)現(xiàn)對響應(yīng)的response進(jìn)行修改(比如進(jìn)行解密處理)
"test": {
    "name": "get token with $user_agent, $os_platform, $app_version",
    "request": {
        "url": "/api/get-token",
        "method": "POST",
        "headers": {
            "app_version": "$app_version",
            "os_platform": "$os_platform",
            "user_agent": "$user_agent"
        },
        "json": {
            "sign": "${get_sign($user_agent, $device_sn, $os_platform, $app_version)}"
        }
    },
    "validate": [
        {"eq": ["status_code", 200]}
    ],
    "setup_hooks": [
        "${setup_hook_prepare_kwargs($request)}",
        "${setup_hook_httpntlmauth($request)}"
    ],
    "teardown_hooks": [
        "${teardown_hook_sleep_N_secs($response, 2)}"
    ]
}
3.hook函數(shù)/勾子函數(shù)的編寫

hook函數(shù)需要在debugtalk.py文件中,依舊是采用$(func($a, $b))的形式去調(diào)用hook函數(shù)

  • 測試用例層面/testcasehook函數(shù)
    在這層面的自定義鉤子函數(shù),可以通過自定義參數(shù)的方式來實(shí)現(xiàn)(就是和普通函數(shù)一樣,無要求)
  • 測試步驟層面/teststephook函數(shù)
    在這層面的自定義鉤子函數(shù),除了可以傳入自定義參數(shù)以外,還可以傳入請求$request和響應(yīng)$response
def hook_print(msg):
    print(msg)
4.測試步驟層面的setup_hooks

除了可以傳入自定義參數(shù)以外,還可以傳入$request,對應(yīng)著當(dāng)前測試步驟$request的所有內(nèi)容。并且因?yàn)?code>$request是可變參數(shù)類型/dict,所以可以通過request["key"]的方式,靈活獲取request的信息。這讓在對請求參數(shù)進(jìn)行預(yù)處理時(shí)更加方便。

  • 官網(wǎng)例子:(疑問:無需返回處理后的請求么?)
def setup_hook_prepare_kwargs(request):
    """
    根據(jù)請求的Content-Type來對請求的data進(jìn)行加工處理
    """
    if request["method"] == "POST":
        content_type = request.get("headers", {}).get("content-type")
        if content_type and "data" in request:
            # if request content-type is application/json, request data should be dumped
            if content_type.startswith("application/json") and isinstance(request["data"], (dict, list)):
                request["data"] = json.dumps(request["data"])

            if isinstance(request["data"], str):
                request["data"] = request["data"].encode('utf-8')

def setup_hook_httpntlmauth(request):
    """
    HttpNtlmAuth權(quán)限授權(quán)。
    """
    if "httpntlmauth" in request:
        from requests_ntlm import HttpNtlmAuth
        auth_account = request.pop("httpntlmauth")
        request["auth"] = HttpNtlmAuth(
            auth_account["username"], auth_account["password"])
5.測試步驟層面的teardown_hooks

同樣的,在測試步驟層面的teardown_hooks函數(shù)中,除了可以傳入自定義參數(shù)以外,還可以傳入response,這個(gè)參數(shù)對應(yīng)當(dāng)前測試步驟的請求的響應(yīng),也就是requests.resposne
經(jīng)常用于對響應(yīng)內(nèi)容進(jìn)行處理,比如說解密、參數(shù)運(yùn)算等,然后再進(jìn)行參數(shù)提取extract和參數(shù)校驗(yàn)validate

  • 比如:首先通過下面這個(gè)函數(shù),把響應(yīng)結(jié)果的狀態(tài)碼和頭部信息進(jìn)行修改;然后再進(jìn)行校驗(yàn)
def alter_response(response):
    response.status_code = 500
    response.headers["Content-Type"] = "html/text"
- test:
    name: alter response
    request:
        url: /headers
        method: GET
    teardown_hooks:
        - ${alter_response($response)}
    validate:
        - eq: ["status_code", 500]
        - eq: ["headers.content-type", "html/text"]
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容