HTTPRunner


  • 概要
  • 安裝
  • 啟動demo server
  • 使用流程
  • 支持腳本錄制
  • 目錄結構(分層原理)
    • 約定大於配置的原則
    • 結構關系
  • 常用命令
  • 腳本結構詳細
    • 測試用例文件說明
    • 腳本詳細說明
      • extract(結果提取器)
  • Validator詳細
  • 腳本參數化–未完待續
    • 列表參數化
    • CSV參數化
    • 自定義函數參數化
  • 熱加載機制
  • Skip機制(分組執行控制測試用例)
    • unittest單元測試框架中的三種常用裝飾器
    • httprunner中的用法
  • 使用技巧
    • 關於報錯
    • 關於yml和json格式
  • 未解決問題
  • 使用中的一些問題和解決方案
  • Version History
    • Ver.1.5.11中的一些變化
  • 那些坑!
    • 坑1
    • 坑2
    • 不算坑,但一點小注意

 

概要

HttpRunner 是一款面向 HTTP(S) 協議的通用測試框架,只需編寫維護一份YAML/JSON腳本,即可實現自動化測試、性能測試、線上監控、持續集成等多種測試需求。

安裝

pip install httprunner(推薦使用python3版本)

啟動demo server

  1. cd到httprunner的目錄,set FLASK_APP=/httprunnerWorkspace/xxxapi_server.py文件地址(非win系統用export)
  2. flask run命令執行后,即可啟動demo server並通過browser訪問

使用流程

  1. 網頁訪問時,通過postman interceptor/Charles/firefox或者chrome的開發者工具來捕獲相關的請求詳情。
  2. 用json/yaml編寫測試用例。
  3. cmd執行測試用例hrun xxxx.json
  4. reports目錄下自動生成測試后的結果報告

支持腳本錄制

  1. 使用Charles>Sequence錄制並導出為.har格式
  2. 轉換生成測試用例 har2case file_path/xxxx.har   new_name.json(也可指定為.yml格式),如果第二個參數省略則默認為json格式
  3. 執行如上腳本即可生成測試報告

目錄結構(分層原理)

約定大於配置的原則

在組織測試用例描述的文件目錄結構時,遵循約定大於配置的原則。通過hrun --startproject project_name創建測試項目目錄后,目錄結構如下:

  • api:API接口定義必須放置在api目錄下
  • suite:模塊定義必須放置在suite目錄下
  • testcases:測試場景文件必須放置在testcases目錄下
  • debugtalk.py: 相關的函數定義放置在debugtalk.py中
接下來,我們就可以按照測試用例的接口-模塊-場景分層原則往里面添加描述信息了。

結構關系

  • api>suite>testcases(在api中定義基本接口及操作,suite中定義suite和調用的api,testcases中直接調用api或者是suite使用)
格式如下:

 

api
[
   {
     "api": {
       "def": "event_add($eid, $name)",
       "validate": [
         {"eq": ["status_code", 200]},
         {"eq": ["content.message", "add event success"]}
       ],
       "request": {
         "url": "/api/add_event/",
         "method": "POST",
         "data": {
           "status": 1,
           "limit": 1000,
           "name": "$name",
           "address": "testemail@email.com",
           "start_time": "2018-09-18 16:00:00",
           "eid": "$eid"
         }
       }
     }
   },
   {
     "api": {
       "def": "event_get($eid, $name)",
       "validate": [
         {"eq": ["status_code", 200]},
         {"eq": ["content.message", "success"]}
       ],
       "request": {
         "url": "/api/get_event_list/",
         "method": "GET",       
         "params": {
           "eid": "$eid",
           "name": "$name"
         }
       }
     }
   }
]

 

suite
[
   {
     "config": {
       "request": {
         "base_url": "http://127.0.0.1:8000"
       },
       "name": "event add get test",
       "def": "event_add_get_suite($eid, $name)"
     }
   },
   {
     "test": {
       "validate": [
         {"eq": ["status_code", 200]},
         {"eq": ["content.message", "add event success"]}
         ],
       "api": "event_add($eid, $name)",
       "name": "event add"
     }
   },
   {
     "test": {
       "validate": [
         {"eq": ["status_code", 200]},
         {"eq": ["content.message", "success"]}],
       "api": "event_get($eid, $name)",
       "name": "event get"
     }
   }
]

 

testcases
[
   {
     "config": {
       "name": "event test",
       "request":{
           "base_url": "http://127.0.0.1:8000/"
       },
       "parameters": [
         {"eid-name": "${P(testcases/eventInfo.csv)}"}
       ]
     }
   },
   {
     "test": {
       "suite": "event_add_get_suite($eid, $name)",
       "name": "event add get details test"
     }
   }
]

 

 

常用命令

命令
詳情
備注
httprunner/hrun hrun -h 核心命令, 通過-h查看命令詳情
  hrun --validate xxxx.json json格式文件的正確性檢測
  hrun --validate xxxx1.json xxxx2.json xxx3.yml 也可以同時指定多個文件,並同時支持json/yaml類型的正確性檢測
  hrun xxx.json --failfast 默認情況會執行所有指定用例集中的所有測試用例,--failfast命令遇到失敗時不再執行后續用例
  hrun xxx.json --log-level debug 查看請求的參數和相應的詳細內容,可將日志級別設置為debug
  hrun xxx.json --html-report-name new_name 指定生成的報告名稱
     
     
har2case ... 格式轉換命令,將har格式轉換成json/yaml格式
     

 

腳本結構詳細

yml
json
- config: name: "xxxxxxx" parameters: - user_agent: ["iOS/10.1", "iOS/10.2", "iOS/10.3"] //列表參數化 - app_version: ${P(app_version.csv)} //csv參數化 - os_platform: ${get_os_platform()} //自定義函數參數化 variables: - user_agent: 'iOS/10.3' - device_sn: ${gen_random_string(15)} - os_platform: 'ios' - app_version: '2.8.6' request: base_url: http://127.0.0.1:5000 headers: Content-Type: application/json device_sn: $device_sn - 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)} extract: - token: content.token validate: - eq: [status_code, 200] - eq: [headers.Content-Type, application/json] - eq: [content.success, true]
[
  {
    "config": {...} }, { "test": {...} }, { "test": {...} } ]
config
"config": {
     "name": "test report title",                  //required; string; 測試用例集的名稱,測試報告的標題
     "parameters": [                                          //optional; list of dict; 全局參數,用於實現數據化驅動,作用域為整個測試用例集
         {"user_agent": ["ios/10.1", "ios/10.2", "ios/10.3"]},
         {"app_version": "${P(app_version.csv)}"},
         {"os_platform": "${get_os_platform()}"}
     ],
     "variables": [                                //optional; list of dict; 定義的全局變量,作用域為整個測試用例集          
         {"user_agent": "ios/10.3"},
         {"device_sn": "${gen_random_string(15)}"},
         {"os_platform": "ios"}
     ],
     "request":{                             //optional; dict of dict; request的公共參數,常用參數包括base_url和headers
         "base_url": "http://127.0.0.1:5000",
         "headers": {
             "Content-Type": "application/json",
             "device_sn": "$device_sn"
         }
     },
     "output": [                      //optional; list of string; 整個用例集輸出的參數列表,可輸出的參數包括variable和extract的參數; 在log-leve為debug模式下,會在terminal中打印出參數內容                  
         "token"
     ]
}
test
"test": {
     "name": " test case title and support $os_platformxxxx",      //required; string; 測試用例的名稱,測試報告中將作為每一項測試的標題
     "request": {                            //required; dict of dict; HTTP請求的詳細內容
         "url": "/api/get-token",
         "method": "POST",
         "headers": {
             "app_version": "$app_version",
             "os_platform": "$os_platform",
             "user_agent": "$user_agent"
         },
         "json": {
             "sign": "$user_agentxxxx"
         },
         "extract": [                    //optional; list of dict; 從當前HTTP請求的相應結果中提取參數,並保存到參數變量中(如token),后續測試用例可以通過&token的形式進行引用
             {"token": "content.token"}
         ],
         "validate": [                 //optional; list of dict; 測試用例中定義的結果校驗項。
             {"eq": ["status_code": 200]},
             {"eq": ["headers.Content-Type", "application/json"]},
             {"eq": ["content.success", true]}
         ],
         "setup_hooks": [],     //optional; list of string; 在HTTP請求發送前執行hook函數,主要用於准備工作。hook函數放置於debugtalk.py中,必須包含三個參數method,url,kwargs(request的參數字典)
         "teardown_hooks": []   //optional; list of string; 在HTTP請求發送后執行hook函數,主要用於測試后的清理工作。hook函數放置於debugtalk.py中,必須包含一個參數,resp_obj:requests.Response實例
     }
}


測試用例文件說明

  • 測試用例集:單個測試用例或多個測試用例的集合,表現形式為一個json文件
  • 測試用例:單次http請求和響應過程,表現形式為json文件中的一個test
  • config:全局配置項,作用於整個測試用例集
  • test:作用於單個測試用例
  • 如果一個變量在config中定義了,在test中沒有定義,則test會繼承該變量
  • 如果一個變量在config和test中都定義了,則test會使用自己定義的變量值
  • 各個test的空間相互獨立,互不影響
  • 如果在多個test之前傳遞參數值,則需要使用extract關鍵字,並且只能從前向后傳遞 
  • 測試用例存在順序關系,運行時從前往后一次運行

腳本詳細說明

  • extract(結果提取器)
      參數提取功能關鍵字extract。如token權限驗證問題,想讓后續的test的token也使用前面test中的token信息時,及可通過參數提取extract。

     

    extract
    "extract": [
            {"token": "content.token"}
       ],
     
     
    ......
    "headers": {
         "token": "$token",
          ........
    },

    只要返回結果是json類型,就可以將其中的任意字段進行提取,並保存到一個變量中,方便后續接口請求進行引用。

*http://cn.httprunner.org/testcase/structure/

 

Validator詳細

No.
Comparator
Description
A(check), B(expect)
1 eq value is equal A == B
2 lt less than A < B
3 le less than or equals A <=B
4 gt greater than A >B
5 ge greater than or equals A >=B
6 ne not equals A != B
7 str_eq string equals str(A) == str(B)
8 len_eq, count_eq length or count equals len(A) == B
9 len_gt,count_gt length greater than len(A) > B
10 len_ge,count_ge length greater than or equals len(A) >= B
11 len_lt, count_lt length less than len(A) < B
12 len_le, count_le length less than or equals len(A) <= B
13 contains contains

[1,2] contains 1

14 contained_by contained by A in B
15 type_match A is instance of B isinstance(A, B)
16 regex_match regex matches re.match(B, A)
17 startwith start with A startwith(B) is True
('abc' startwith 'ab')
18 endswith ends with A endswith(B) is True
('abc' endswith 'bc')

 

腳本參數化–未完待續

定義參數時,需要使用parameters關鍵字。

  • $變量轉義符
  • ${}函數轉義符,可以直接填寫函數名稱及調用參數,還可以包含變量

列表參數化

yml
有關聯的yml列表參數化
json
有關聯的json列表參數化
- config: parameters: - var1: ["iOS/10.1", "iOS/10.2", "iOS/10.3"] 
- test:
request:
method:POST
data:
var1:$var1
validate:
- eq:
- content.body.param.var1
- $var1
- config: parameters: - var1-var2:
- ["var1stri","var2stri"]
- ["var2stri","var2stri"]
- test:
request:
method:POST
data:
var1:$var1
var2:$var2
validate:
- eq:
- content.body.param.var1
- $var1

 

[
  {
    "config": {
"parameters": ["varxxx","varxxx"]} }, { "test": {...} } ]

 

[
  {
    "config": {
"parameters": "[
{"var1-var2":[["var1str","var2str"],["var1stri","var2stri"]]}
]"} }, { "test": {
"request":{
"data":{
"var1":"$var1",
"var2":"$var2"
}
}
} } ]

CSV參數化

yml
-   config:
         parameters:
             - eid-name: ${P(add.csv)}//關聯參數
 
 
-   test:
         request:
             data:
                 address: dalian
                 eid: '$eid'
                 limit: '1000'
                 name: '$name'
                 start_time: '2018-07-17 18:00:00'
                 status: '1'
             method: POST
             url: http://127.0.0.1:8000/api/add_event/
         validate:
         -   eq:
             - status_code
             - 200
         -   eq:
             - content.message
             - add event success
json
"config": {                       
             "parameters": [
                 {
                     "eid-name": "${P(add.csv)}" //關聯參數
                 }
             ]
         }
.......
"test": {
             "validate": [
                 {
                     "eq": ["status_code",200]
                 },
                 {
                     "eq": [
                         "content.status",
                         200
                     ]
                 },
                 {
                     "eq": [
                         "content.message",
                         "add event success"
                     ]
                 }
             ],
             "request": {
                 "data": {
                     "status": "1",
                     "limit": "1000",
                     "name": "$name",
                     "address": "dalian",
                     "start_time": "2018-07-17 18:00:00",
                     "eid": "$eid"
                 },
                 "method": "POST"
             },
             "name": "/api/add_event/"
         }


自定義函數參數化

debugtalk.py中自定義參數,腳本中使用參數后,報錯

httprunner.exceptions.FunctionNotFound: get_parame_info not found in debugtalk.py module!
module mapping: {'variables': {}, 'functions': {}}

關注這個問題,需要持續關注https://testerhome.com/opensource_projects/httprunner上對DarkLi的回答

 

熱加載機制

某些校驗功能沒有實現時,需要使用自定義的函數。

從熱加載的順序可以看出,查找變量或函數的順序是從測試用例所在目錄開始,沿着父路徑逐層往上,直到系統的根目錄。
因此,我們可以利用這個優先級原則來組織我們的用例和依賴的Python函數模塊。將不同模塊的測試用例集文件放在不同的文件夾下:
針對各個模塊獨有的依賴函數和變量,可以放置在對應文件夾的debugtalk.py文件中;而整個項目公共的函數和變量,就可以放置到項目文件夾的debugtalk.py中。

注意:因為我們在框架運行過程中需要將debugtalk.py作為函數模塊進行導入,因此我們首先要保障debugtalk.py滿足Python模塊的要求,
         也就是在對應的文件夾中要包含__init__.py文件

  • 導入python模塊的關鍵詞:import_module_items
  • 不需要顯示指定導入的python模塊路徑,熱加載機制會自動發現。

Skip機制(分組執行控制測試用例)

unittest單元測試框架中的三種常用裝飾器

  • @unittest.skip(reason) :無條件跳過當前測試用例
  • @unittest.skipIf(condition,reason) : 當條件表達式的值為true時跳過當前測試用例
  • @unittest.skipUnless(condition,reason): 當條件表達式的值為false時跳過當前測試用例

httprunner中的用法

因為httprunner同樣也是采用unittest來組織和驅動測試用例執行的,那么使用方法如下。

  • skip 無條件的:在測試用例中新增skip字段(skip:"skip this test unconditionally")
    skipIf和skipUnless的condition這樣的函數表達式調用會稍微麻煩一些,在debug.py中定義了skip_test_in_prodection_env()。
  • skifIf 有條件的: 在測試用例中新增 skipIf: ${skip_test_in_production_env()}
  • skipUnless 有條件的: 在測試用例集中新增 skipUnless: ${skip_test_in_production_env()}

使用技巧

關於報錯

  • 報錯詳情里提示錯誤詳情時,不要首先懷疑源碼,debug查看詳情后再做進一步判斷(hrun xxx.json --log-level debug)
  • 如果想保留debug level的信息輸入為文件,可以兩個命令組合使用(hrun xxx.json --log-level debug --log-file log_name.txt)

關於yml和json格式

httprunner網上多用yml格式編輯,如果case做成時json腳本執行不通過的情況,可以采用如下方式轉換為正確的json類型。

  1. 參照規范做成yml格式的腳本並保證執行ok
  2. 用在線工具將yml轉成json格式http://yaml-online-parser.appspot.com/
  3. 執行json格式腳本

*同時可用--prettify命令來美化json格式

未解決問題

  • python操作csv文件
  • 結合jenkins使用
  • 報告自定義模板
  • 性能測試Locusts應用需要時,再研究用法(目前停留在啟動locusts服務后web localhost:8089頁面css亂)

使用中的一些問題和解決方案

  • 在報錯Error: test_0000_0000(httprunner.api,TestSequense), TypeError: request() got an unexpected keyword argument 'validate'時
    優先check一下腳本層級是否有問題。有的時候雖然用–validate命令check ok,但實際上腳本仍然有問題。

Version History

Ver.1.5.11中的一些變化

  • 一個項目只能有一個debugtalk.py文件。運行時,首先定位debugtalk.py,將其所在目錄作為項目的根目錄
  • 在YAML/JSON測試用例中,CSV文件的路徑是相對於根目錄的路徑。如,引用csv參數的測試用例中的路徑寫法應為${P(testcases/eventInfo.csv)}

那些坑!

坑1

是的,怎么能少了那些坑呢,果然又一次趴坑了。趴坑里一天多,終於解決了!

現象:json csv參數化時,腳本執行一直報錯KeyError: 'name'。於是乎一直以為參數傳遞的方式有問題,其實不是,不是,不是!!!!!

原因:json腳本格式不正確。一定要注意腳本中各關鍵字之間的層級關系。如name關鍵字並不在request中;validate也不在request中。

坑2

測試用例分層執行時,如果依然在.../tests/testcases目錄下執行,會報api not found的error。

原因:分層測試case之前,需要先加載api和suite的內容

解決方案:分層測試用例執行時,必須先cd到根目錄下(testproject), 再用hrun tests/testcases/xxx.json的命令形式來執行。

如,hrun F:/Python3Workspace/testproject/tests/testcases/usersigntest.json

不算坑,但一點小注意

get方法時,request中的參數數據關鍵字不是json也不是data,而是params。當不明確request中請求的關鍵字時可以用charles錄制api,轉成json查看關鍵字。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM