test-express
接口自动化测试框架。采用 python3,基于 httprunner 开发。
特性
- 继承 Requests 的全部特性,轻松实现 HTTP(S) 的各种测试需求
- 测试用例与代码分离,采用 YAML(推荐)/JSON 的形式描述测试场景,保障测试用例具备可维护性
- 测试用例支持分层机制,充分实现测试用例的复用
- 测试用例支持参数化和数据驱动机制
- 支持热加载机制,在文本测试用例中轻松实现复杂的动态计算逻辑
- 测试结果统计报告简洁清晰,附带详尽统计信息和日志记录
安装
使用前,请先安装相关依赖库
pip3 install -r [项目根目录]/requirments.txt
安装检验
运行如下命令,若正常显示版本号,则说明 HttpRunner 安装成功。
$ hrun -V
>>> 2.5.7
约定
工作空间/项目 结构
推荐结构
- api # 接口描述文件
- login_api.yml
- get_nodes_api.yml
- testcases # 用例描述文件
- get_nodes.yml
- testsuites # 套件描述文件
- debugtalk.py # 用于存放自定义函数
- .env # 用于配置环境变量
- data # 用于存放用例数据
- account.csv
- reports # 存储 html 测试报告
使用概述
使用步骤
- 根据接口和测试目的编写用例描述文件(推荐yaml), like "get_nodes.yml"
- 执行 yaml 文件
hrun /path/to/get_nodes.yml
- 拿到测试报告
每次运行完后,在当前目录的 reports 目录下找到最新的 html 报告
- done.
如何编写用例描述文件是重点
概念
开始编写用例描述文件之前,有必要对相关概念作简要说明。
- 测试步骤
- 测试用例
- 测试套件
测试步骤(teststep)
对于接口测试来说,每一个测试步骤就对应一个 API 的请求描述。
have a look
login_api.yml,登录接口
name: login
base_url: ${ENV(BASE_URL)}
variables:
expected_status_code: 200
content_code: 0
username: "visitor"
password: "v123456"
request:
method: POST
url: /user/login/
headers:
Content-Type: "application/json"
json:
username: $username
password: $password
validate:
- eq: [status_code, $expected_status_code]
- eq: [headers.Content-Type, application/json]
- eq: [content.code, $content_code]
# - len_eq: [content.token, 5]
- contains: [content.data, "token"]
extract:
token: content.data.token
测试步骤关键字说明
key | required | format | description |
---|---|---|---|
name | Yes | string | 测试步骤的名称,在测试报告中将作为测试步骤的名称 |
request | Yes | dict | HTTP 请求的详细内容;可用参数详见 python-requests 官方文档 |
variables | No | list of dict | 测试步骤中定义的变量,作用域为当前测试步骤 |
extract | No | list | 从当前 HTTP 请求的响应结果中提取参数,并保存到参数变量中(例如token),后续测试用例可通过$token的形式进行引用 |
validate | No | list | 测试用例中定义的结果校验项,作用域为当前测试用例,用于实现对当前测试用例运行结果的校验 |
setup_hooks | No | list | 在 HTTP 请求发送前执行 hook 函数,主要用于准备工作 |
teardown_hooks | No | list | 在 HTTP 请求发送后执行 hook 函数,主要用户测试后的清理工作 |
extract
支持多种提取方式
- 响应结果为 JSON 结构,可采用.运算符的方式,例如headers.Content-Type、content.success;
- 响应结果为 text/html 结构,可采用正则表达式的方式,例如blog-motto">(.*)
validate
断言/验证
"comparator_name": [check_item, expect_value]
short | comparator | description |
---|---|---|
eq | equals | 判断实际结果和期望结果是否相等 |
lt | less_than | 判断实际结果小于期望结果 |
le | less_than_or_equals | 判断实际结果小于等于期望结果 |
gt | greater_than | 判断实际结果大于期望结果 |
ge | greater_than_or_equals | 判断实际结果大于等于期望结果 |
ne | not_equals | 判断实际结果和期望结果不相等 |
str_eq | string_equals | 判断转字符串后对比 实际结果和期望结果是否相等 |
len_eq | length_equals | 判断字符串或list长度 |
len_gt | length_greater_than | 判断实际结果的长度大于和期望结果 |
len_ge | length_greater_than_or_equals | 实际结果的长度大于等于期望结果 |
len_lt | length_less_than | 实际结果的长度小于期望结果 |
len_le | length_less_than_or_equals | 实际结果的长度小于等于期望结果 |
hooks
- setup_hooks 函数放置于 debugtalk.py 中,并且必须包含三个参数:
- method: 请求方法,e.g. GET, POST, PUT
- url: 请求 URL
- kwargs: request 的参数字典
- teardown_hooks 函数放置于 debugtalk.py 中,并且必须包含一个参数:
- resp_obj: requests.Response 实例
request 关键字
key | required | format | description |
---|---|---|---|
base_url | No | string | 测试用例请求 URL 的公共 host,指定该参数后,test 中的 url 可以只描述 path 部分 |
headers | No | dict | request 中 headers 的公共参数,作用域为整个用例 |
export | No | list | 整个用例输出的参数列表,可输出的参数包括公共的 variable 和 extract 的参数; 在 log-level 为 debug 模式下,会在 terminal 中打印出参数内 |
测试用例(testcase)
引用来自 wiki 的定义:
测试用例(testcase)应该是为了测试某个特定的功能逻辑而精心设计的,并且至少包含如下几点:
- 明确的测试目的(achieve a particular software testing objective)
- 明确的输入(inputs)
- 明确的运行环境(execution conditions)
- 明确的测试步骤描述(testing procedure)
- 明确的预期结果(expected results)
在本框架中,测试用例是测试步骤的 有序 集合。
get_nodes.yml,获取 node 列表的用例
config:
name: "get nodes"
variables:
username: "visitor"
password: "v123456"
base_url: ${ENV(BASE_URL)}
teststeps:
- name: 第一步,登录
api: api/maseeper/login_api.yml
variables:
expected_status_code: 200
content_code: 0
validate:
- eq: ["status_code", $expected_status_code]
- eq: [content.code, $content_code]
extract:
- token: content.data.token
- name: 第二步,获取 nodes
api: api/maseeper/get_nodes_api.yml
variables:
token: $token
username: $username
- teststeps,测试步骤的有序集合
- config,为文件内的全局配置项
config 关键字说明
key | required | format | description |
---|---|---|---|
name | Yes | string | 用例名称,作为报告中的标题 |
parameters | No | list of dict | 用于实现数据化驱动 |
variables | No | list of dict | 定义的全局变量,作用域为整个用例 |
request | No | dict | request 的公共参数,常用参数包括 base_url 和 headers |
变量空间作用域
- 测试步骤的变量空间(context)会继承或覆盖 config 中定义的内容;
- 若某变量在 config 中定义了,在某 test 中没有定义,则该 test 会继承该变量
- 若某变量在 config 和某 test 中都定义了,则该 test 中使用自己定义的变量值
- 各个测试步骤(test)的变量空间相互独立,互不影响;
- 如需在多个测试步骤(test)中传递参数值,则需要使用 extract 关键字,并且只能从前往后传递
录制生成测试套件
- 安装 har2case;
# install
$ pip install har2case
# check
$ har2case -V
>>>0.2.1
-
将抓包工具拿到的数据包导出为 HAR 格式的文件,like: login.har。
通过 har2case 将 har 文件 转为 测试用例文件。
$ har2case docs/data/demo-quickstart.har -2y
INFO:root:Start to generate testcase.
INFO:root:dump testcase to YAML format.
INFO:root:Generate YAML testcase successfully: docs/data/demo-quickstart.yml
测试套件(testsuite)
测试用例集 是 测试用例 的 无序 集合,集合中的测试用例应该都是相互独立,不存在先后依赖关系的。
config:
name: "maseeper testsuite"
variables:
username: "visitor"
password: "v123456
base_url: ${ENV(BASE_URL)}
testcases:
- name: "获取 nodes"
testcase: testcases/maseeper/get_nodes.yml
variables:
device_sn: $device_sn
- name: "获取 envs"
testcase: testcases/maseeper/get_envs.yml
variables:
expected_status_code: 200
content_code: 0
parameters:
expected_status_code: [200, 201]
content_code: [0, 1, 2]
- testcases,测试用例的无序集合
parameters
参数化场景
当前版本只支持 testsuite 层。
参数化后,parameters 中的变量将采用笛卡尔积组合形成参数列表,依次覆盖 variables 中的参数,驱动测试用例的运行。
组织结构
组织结构涉及三个基础概念:
- 测试套件
- 测试用例
- 测试步骤
三者的关系
- 测试套件包含多个/一个测试用例(YAML/JSON)
- 一个测试用例包含多个/一个测试步骤(STEP)
- 测试步骤对应YMAL/JSON文件中的 teststeps 子项,包含单个接口的全部内容,包括发起请求,解析响应结果,校验结果。
环境变量
终端环境变量
set
使用环境变量之前,需要先在系统中设置环境变量名称和值,传统的方式为使用 export 命令(Windows系统中使用 set 命令)
$ export UserName=admin
$ echo $UserName
admin
get
在程序中就可以对系统中的环境变量进行读取。
$ python
>>> import os
>>> os.environ["UserName"]
'admin'
.env 环境变量
默认情况下,在自动化测试项目的根目录中,创建 .env 文件,并将敏感数据信息放置到其中,存储采用 name=value 的格式。
set
$ cat .env
UserName=admin
Password=123456
PROJECT_KEY=ABCDEFGH
get
在用例描述文件中 引用 .env文件中的变量。
${ENV(UserName)}
附录
httprunner 手册