本文正在參加「Python主題月」,詳情查看 活動連接html
今天來介紹一個python的一個開源項目:httprunner,接口自動化工具。第一次輸入,不免有不周到的地方,輕噴~python
HttpRunner是一個簡單優雅但功能強大的 HTTP(S) 測試框架。以YAML或JSON格式定義測試用例,保障測試用例描述的統一性和可維護性。程序執行的時候,會處理用戶輸入的yml/json文件並基於模板生成測試文件。最終經過pytest.main([])的方式去執行生成的用例文件。用戶只須要經過json/yml文件去維護用例便可,不須要關心程序如何處理json/yml文件,如何生成測試文件等,簡單快速經過pytest運行用例,並獲取詳細的測試報告。git
想要了解其工做流程,最好的辦法就是使用debug模式,那在這裏應該如何使用debug來參透httprunner的執行流程呢?跟着我來看下:github
使用pycharm進行調試,且python環境使用Virtualenv進行管理shell
/venv/bin/
目錄下找到hrun文件sys.exit(main_hrun_alias())
這裏打個斷點,那麼就能夠開始愉快的調試之旅了~# -*- coding: utf-8 -*-
import re
import sys
from httprunner.cli import main_hrun_alias
if __name__ == '__main__':
sys.argv = ['/Users/boyizhang/PycharmProjects/apitest/venv/bin/hrun', '/Users/boyizhang/PycharmProjects/apitest/hruntests/testcases/testheader.yml']
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(main_hrun_alias())
複製代碼
調試日誌:json
歸納來講,測試用例分層機制的核心是將接口定義、測試步驟、測試用例、測試場景進行分離,單獨進行描述和維護,從而儘量地減小自動化測試用例的維護成本。api
建議你們用最新版本的,可是有興趣瞭解httprunner的架構變化的同窗,能夠繼續讀V2.0模塊的內容。數組
V2.0的版本中,存在api definition的概念。bash
優勢是:api管理方便;缺點是:在testcase中的teststep能夠直接引用api definition,無論testcase是單個步驟的簡單場景仍是多個步驟的複雜場景,都須要進行引用api definition。這樣的話,對於單個步驟的簡單場景而言,又和api definition很類似,這樣就會形成重複描述,並且容易混淆。 **markdown
那麼,咱們如何在testcase>teststep中引用api呢?如何引用testcase呢? **
在teststep中能夠經過api字段引用api definition 、經過testcase字段引用testcase。下面咱們根據腳手架快速建立一個項目httprunner --startproject hruntest2.0
(須要確保安裝的是httpruner3.0如下的版本)來講明:
$ httprunner --startproject hruntest2.0 && tree hruntest2.0
Start to create new project: hruntest2.0
CWD: /Users/boyizhang/PycharmProjects/apitest
created folder: hruntest2.0
created folder: hruntest2.0/api
created folder: hruntest2.0/testcases
created folder: hruntest2.0/testsuites
created folder: hruntest2.0/reports
created file: hruntest2.0/api/demo_api.yml
created file: hruntest2.0/testcases/demo_testcase.yml
created file: hruntest2.0/testsuites/demo_testsuite.yml
created file: hruntest2.0/debugtalk.py
created file: hruntest2.0/.env
created file: hruntest2.0/.gitignore
hruntest2.0
├── api
│ └── demo_api.yml
├── debugtalk.py
├── reports
├── testcases
│ └── demo_testcase.yml
└── testsuites
└── demo_testsuite.yml
複製代碼
# api/demo_api.yml
name: demo api
variables:
var1: value1
var2: value2
request:
url: /api/path/$var1
method: POST
headers:
Content-Type: "application/json"
json:
key: $var2
validate:
- eq: ["status_code", 200]
複製代碼
config:
name: "demo testcase"
variables:
device_sn: "ABC"
username: ${ENV(USERNAME)}
password: ${ENV(PASSWORD)}
base_url: "http://127.0.0.1:5000"
teststeps:
-
name: demo step 1
api: path/to/api1.yml
variables:
user_agent: 'iOS/10.3'
device_sn: $device_sn
extract:
- token: content.token
validate:
- eq: ["status_code", 200]
複製代碼
在teststep中使用api選項來引用api definition,執行testcase/demo_testcase.yml用例文件。(注:api definition不屬於testcase範疇,沒法直接執行api/下的yml/json文件)。在teststep中傳的字段的優先級會比api definition下的高,也就是說,若是teststep傳某個字段,那麼會有限使用teststep傳的那個,若是沒有,則再使用api definition的字段。
爲了簡單,在HttpRunner v2.x中的API概念已經被取消了。能夠將API定義爲只有一個請求步驟的測試用例**(須要重點注意一下這裏)**。
那麼,問題來了,咱們應該如何在某個testcase的teststep中引用其餘testcase呢?
在測試步驟(teststep)中,可經過 testcase 字段引用其它測試用例,引用方式爲對應測試用例文件的路徑,絕對路徑或相對路徑都可。推薦使用相對路徑,路徑基準爲項目根目錄,即 debugtalk.py 所在的目錄路徑。
**經過 **httprunner startproject hruntest3.0
快速建立項目。
$ tree hruntest3.0
hruntest3.0
├── debugtalk.py
├── har
├── reports
└── testcases
├── demo_testcase_ref.yml
└── demo_testcase_request.yml
複製代碼
# demo_testcase_request.yml
config:
name: "request methods testcase with functions"
variables:
foo1: config_bar1
foo2: config_bar2
expect_foo1: config_bar1
expect_foo2: config_bar2
base_url: "https://postman-echo.com"
verify: False
export: ["foo3"]
teststeps:
-
name: post form data
variables:
foo2: bar23
request:
method: POST
url: /post
headers:
User-Agent: HttpRunner/${get_httprunner_version()}
Content-Type: "application/x-www-form-urlencoded"
data: "foo1=$foo1&foo2=$foo2&foo3=$foo3"
validate:
- eq: ["status_code", 200]
- eq: ["body.form.foo1", "$expect_foo1"]
- eq: ["body.form.foo2", "bar23"]
- eq: ["body.form.foo3", "bar21"]
複製代碼
# demo_testcase_ref.yml
config:
name: "request methods testcase: reference testcase"
variables:
foo1: testsuite_config_bar1
expect_foo1: testsuite_config_bar1
expect_foo2: config_bar2
base_url: "https://postman-echo.com"
verify: False
teststeps:
-
name: request with functions
variables:
foo1: testcase_ref_bar1
expect_foo1: testcase_ref_bar1
testcase: testcases/demo_testcase_request.yml
export:
- foo3
-
name: post form data
variables:
foo1: bar1
request:
method: POST
url: /post
headers:
User-Agent: HttpRunner/${get_httprunner_version()}
Content-Type: "application/x-www-form-urlencoded"
data: "foo1=$foo1&foo2=$foo3"
validate:
- eq: ["status_code", 200]
- eq: ["body.form.foo1", "bar1"]
- eq: ["body.form.foo2", "bar21"]
複製代碼
在teststep中使用testcase字段來引用,執行demo_testcase_ref.yml用例文件,當執行到name = request with functions這個步驟的時候會先執行其引用的testcase:testcases/demo_testcase_request.yml
。 在根目錄下,執行hrun testcases/demo_testcase_ref.yml
,能夠看到,程序也生成了該case:testcases/demo_testcase_request.yml
的測試文件:
涉及hook處理
在自動化測試中,執行用例前,須要執行一些預處理操做,執行用例後,須要作一些清理工做。若是手動去操做的話,就不是很合適。因此就須要用到hook機制,在執行用例先後執行hook函數。
hook 機制分爲兩個層級:
編寫hook函數
${print_req(``$request``)}
。# ${print_request($request)}
2021-07-18 09:30:46.740 | DEBUG | httprunner.runner:__call_hooks:121 - call hook function: ${print_reqeust($request)}
{'method': 'GET', 'url': '/get', 'params': {'foo1': 'bar11', 'foo2': 'bar21', 'sum_v': 3}, 'headers': {'User-Agent': 'HttpRunner/3.1.5', 'HRUN-Request-ID': 'HRUN-7768261f-0abf-4ce5-abf2-06327de85fd7-846739'}, 'req_json': None, 'data': None, 'cookies': {}, 'timeout': 120, 'allow_redirects': True, 'verify': False}
# ${print_req($response)}
2021-07-18 09:36:03.019 | DEBUG | httprunner.runner:__call_hooks:121 - call hook function: ${print_req($response)}
<httprunner.response.ResponseObject object at 0x109c87e50>
複製代碼
涉及env的處理,文檔
# parser.py
def get_mapping_function( function_name: Text, functions_mapping: FunctionsMapping ) -> Callable:
#省略
if function_name in functions_mapping:
return functions_mapping[function_name]
elif function_name in ["environ", "ENV"]:
return utils.get_os_environ
#省略
raise exceptions.FunctionNotFound(f"{function_name} is not found.")
# utils.py
def set_os_environ(variables_mapping):
""" set variables mapping to os.environ """
for variable in variables_mapping:
os.environ[variable] = variables_mapping[variable]
logger.debug(f"Set OS environment variable: {variable}")
def get_os_environ(variable_name):
try:
return os.environ[variable_name]
except KeyError:
raise exceptions.EnvNotFound(variable_name)
複製代碼
加載用例以前,會先把.env文件中的變化加載到環境中,若是用例用含有ENV或者environ,則經過os.environ
去讀取相應的值。
HttpRunner 實現參數化數據驅動機制:debugtalk.com/post/httpru… HttpRunner 再議參數化數據驅動機制:debugtalk.com/post/httpru…
須要注意的是,從v2.0開始,參數化只支持在 testsuite 中實現。再也不支持在測試用例文件中進行參數化配置。
參數配置概述
具體使用 v2.httprunner.org/prepare/par…
底層使用jmespath ,提取和驗證json響應,使得提取更簡單。 extract用來抓取響應體中的字段,export導出當前用例抓取的字段,供引用該用例的用例使用。
好好利用httprunner,能夠覆蓋80%的場景,能夠說是一個不錯的工具,固然咱們除了學習應該如何使用以外,更應該學習人家設計的思想,這樣本身以後纔能有機會作好一點的工具。 另外推薦一個Java版本的接口自動化工具你們能夠參考rest-assured。httprunner與rest-assured實現方式大同小異,不過rest-assured並無經過json/yaml去管理用例,而是直接寫測試文件(相似httprunner生成的py文件)。你們能夠對比學習下~。