本文正在参加「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文件)。你们能够对比学习下~。