HttpRunner 是一款面向 HTTP(S) 协议的通用测试框架,只需编写维护一份YAML或JSON脚本,即可实现自动化测试、性能测试、线上监控、持续集成等多种测试需求
特点
pip install httprunner # 安装httprunner,若下载失败请使用国内源下载
hrun -V # 查看httprunner版本
# 版本显示正确表示安装完成,执行以下命令,通常安装httprunner时会一并安装,若不存在请通过pip命令单独安装
har2case -V # 查看har2case版本
locusts -V # 查看locust版本
安装完成后以下5个命令会自动写入系统环境变量中,无需手动配置
httprunner
:主命令,用于所有功能
hrun
:指令httprunner run
的别名,用于运行YAML/JSON/Pytest 测试用例
hmake
: 指令httprunner make
的别名,将YAML/JSON用例转换成pytest用例
har2case
:指令httprunner har2case
的别名,将HAR文件转换成 YAML/JSON 用例
locust
: 利用locust运行性能测试
HttpRunner3.x支持三种格式的测试用例:YAML、JSON以及Pytest(python)
以YAML为例,先简单介绍下YAML,YAML支持注释、换行、多行字符串、单行字符串等,比JSON更简洁、更直观、可读性更高
YAML的语法规则:
支持的数据类型:
对象:键值对的集合,又称为映射(mapping)/ 哈希(hashes) / 字典(dictionary)
key: # 键值之间的冒号后面需要有空格
child-key: value
child-key2: value2
数组:一组按次序排列的值,又称为序列(sequence) / 列表(list)
- # 以 - 开头的行表示构成一个数组,如下为两组数据
- A # 第一组数据只有A,A又独为一组
- # 第二组数据有B和C,B和C又各为一组
- B
- C
纯量(scalars):单个的、不可再分的值
# 字符串、布尔值、整数、浮点数、时间等属于纯量
string:
- 这是字符串
- 'Hello world' #可以使用双引号或者单引号包裹特殊字符
- newline
newline2 #字符串可以拆成多行,每一行会被转化成一个空格
int:
- 123
- 0b1010_0111_0100_1010_1110 #二进制表示
引用
&
用来建立锚点,<<
表示合并到当前数据,*
用来引用锚点
defaults: &default # 建立锚点,数据变更时只需修改此锚点,引用锚点无需修改,减少修改量
adapter: postgres
host: localhost
development:
database: myapp_development
<<: *default # 引用锚点并合并到当前数据,避免数据重复
test:
<<: *default # 引用锚点并合并到当前数据
可通过先快速搭建个脚手架,使用命令httprunner startproject 项目名称
,例如在PyCharm终端输入httprunner startproject APItesting
就会生成如下图中的项目结构
以实际项目为例,请通过注释了解测试用例结构及编写方法
# Secgroup.yml文件
config: # 全局配置,每个测试用例都必须有config部分
name: 安全组业务流接口测试 # 用例描述,name是必须要有的,其它配置项为可选项,根据实际项目增删
base_url: http://192.166.66.22 # 项目路径,亦可配置在环境配置env文件中
variables: # 参数配置
Opertype: ADD
poolId: e3cc3d8b90b4465998ddfec569a66612
resType: SECURITYGROUP
name: dyd${random_num()} # 此处调用了在debugtalk.py中定义的生成随机数的函数
secGType: SECURITY_VM
adapterType: SINGLE
approvalType: SECURITYGROUP-ADD
teststeps: # 每个测试用例都有1个或多个测试步骤,name,request是必须有的,其它根据实际项目配置
- name: 登录平台 # 步骤一,登录平台
request: # 配置请求信息,(请求方法、url、头信息、传参等)
method: POST
url: /users/login # 因全局配置中已存在base_url,故在测试步骤不必填写,其会自动拼接
headers:
SID: dy5eabbbf8eb496dd7788664f8322c8e
json: # 入参参数
username: ${ENV(username)} # 引用env环境配置中的账号和密码
password: ${ENV(password)}
extract: # 提取响应数据中的access_token值
access_token: body.entity.access_token # # body是响应体json的根节点
validate: # 判断是否成功,可使用多个断言
- eq: [body.success,true]
- eq: [status_code, 200]
- name: 创建安全组 # 步骤二,创建安全组,每个步骤格式都差不多,根据实际项目做修改即可
request:
method: POST
url: /dy/adapter
headers: &header # 建立锚点
Authorization: Bearer $access_token # 调用步骤一登录后获得的token
SID: dy5eabbbf8eb496dd7788664f8322c8e
json: # 入参参数,也可直接写json格式
adapterTargets:
- level: $Opertype # 调用全局配置中的参数
poolId: $poolId
resourceType: $resType
resourceProperties:
name: $name
securityGroupType: $secGType
adapterType: $adapterType
approvalType: $approvalType
validate: # 断言是否成功
- eq: [body.success,true]
- eq: [status_code, 200]
- name: 查看安全组列表 # 步骤三,查看列表是否新增创建的安全组
request:
method: POST
url: /dian/security-groups
headers:
<<: *header # 引用锚点并合并到headers下
json: # 传参
pageNum: 1
pageSize: 5
extract: # 提取列表中第一个安全组的id,有用到下标查找
secg_id: body.entity.list.0.id
validate: # 断言
- eq: [body.success,true]
- eq: [status_code, 200]
- contains: [body.entity.list.0.name,dyd] # 判断第一条安全组的名字是否包含创建时的关键字
- name: 查看安全组详情 # 步骤四,查看新创建的安全组详情
request:
method: GET
url: /dian/security-groups/$secg_id # 调用步骤三中提取的安全组id并与url拼接
headers:
<<: *header # 引用锚点并合并到headers下
validate: # 断言
- eq: [body.success,true]
- eq: [status_code, 200]
- contains: [body.entity.name,dyd] # 判断安全组详情中的安全组名称是否包含dyd
上面示例中用到了env文件和debugtalk.py文件
通常在自动化测试项目的根目录中创建 .env 文件,并将敏感数据信息放置到其中,存储采用 name=value 的格式,通过脚手架生成的接口测试项目中,会自动生成.env文件,可直接在.env中添加环境变量,.env文件中除注释外,其它行都不允许存在空格,引用环境变量的方法${ENV(name)}
debugtalk.py文件名称不能变更,通过脚手架生成的接口测试项目中也会自动生成,在此文件中写python脚本,然后在YAML文件中调用,调用方法${func()}
,例如上文中用到的随机数${random_num()}
import random
def random_num():
return random.randint(1,10)
支持多种参数化方式,如.env、debugtalk.py、csv等,此处仅介绍Pytest中的参数化方式,如下示例:
# login.yml文件
config:
name: 参数化测试登录接口
parameters: # 多个参数具有关联性的参数需要将其定义在一起,采用短横线(-)进行链接
user-pwd-msg:
- ["admin","VCfa……gnw==",null]
- ["nimda","VCfa……gnw==","用户不存在或者已冻结"]
- ["admin","123456","解密失败,请确认传输加密方式"]
# username: ["admin","nimda","adnim"] 单个参数参数方式
teststeps:
- name: 登录验证
request:
method: POST
url: ${ENV(HOST)}/users/login # 引用env环境配置中的HOST
headers:
SID: dy5eabbbf8eb496dd7788664f8322c8e
json:
username: $user # 调用全局配置中的参数进行传参
password: $pwd
validate:
- eq: [ body.message,$msg ] #调用全局配置中的msg参数,判断是否与响应结果一致
- eq: [ body.message,$msg ]
- eq: [ body.message,$msg ]
hook机制可以在请求前和请求后调用钩子函数,跟Pytest中的setup/teardown类似,hook机制分为两个层级:
(1)测试用例层面:在YAML/JSON测试用例的config中新增关键字setup_hooks和teardown_hooks
(2)测试步骤层面:在YAML/JSON测试步骤teststeps中新增关键字setup_hooks和teardown_hooks
hook函数的定义是放置在项目的debugtalk.py中,在YAML/JSON中调用hook函数同样是采用${func($a, $b)}
的形式,如下示例
# debugtalk.py中增加以下代码
def setupHook(request):
print("**********开始执行测试用例**********")
print("request请求:{}".format(request))
def teardownHook(response):
print("**********修改响应结果后再进行断言**********")
response.status_code = 300
response.body["success"] = "false"
# get_token.yml文件
config:
name: 获取token认证信息
teststeps:
- name: 获取token
setup_hooks: # 调用hook函数
- ${setupHook($request)}
teardown_hooks:
- ${teardownHook($response)}
request:
method: POST
url: ${ENV(HOST)}/oauth/token # 引用env环境配置中的HOST
headers:
SID: dy5eabbbf8eb496dd7788664f8322c8e
data:
username: admin
password: 123456
extract:
token: body.entity.access_token # 提取响应结果中的token值
validate:
- eq: [status_code,200]
- eq: [body.success,true]
执行后能够获得正确结果,但是因为teardown_hooks在断言前把响应结果改了,所以会返回断言失败的报错信息
可以使用requests库在debugtalk.py写请求接口,获取token,然后可通过${func()}
调用,也可通过setup_hooks调用,实际情况需根据接口而定
# debugtalk.py中增加以下代码
import requests
def getToken():
url = "http://192.166.66.22/oauth/token"
header = {"SID": "dy5eabbbf8eb496dd7788664f8322c8e"}
data = {"username": "admin",
"password": "123456"}
res = requests.post(url,headers=header,data=data).json()
return res["entity"]["access_token"]
# keypair.yml文件
config:
name: 测试获取SSH密钥列表接口
teststeps:
- name: 获取SSH密钥列表
request:
headers: &header # 建立锚点
Authorization: Bearer ${getToken()} # 调用debugtalk.py中的getToken()
SID: dy5eabbbf8eb496dd7788664f8322c8e
json:
pageNum: 1
pageSize: 10
method: POST
url: ${ENV(HOST)}/dian/keypairs # 引用env环境配置中的HOST
validate: # 断言
- eq: [body.success,true]
- name: 上传密钥文件
request:
method: POST
url: ${ENV(HOST)}/dian/keypairs/file # 引用env环境配置中的HOST
headers:
<<: *header # 引用锚点并合并到当前数据
upload: # 上传文件
file: "data/csb-dyd.pem"
field: "value"
validate: # 断言
- eq: [ status_code, 200 ]
hrun testcases/Secgroup.yml # 运行指定路径的用例
hrun testcases/get_token.yml testcases/keypair.yml # 运行指定路径的多个用例
hrun testcases # 运行testcases目录下所有的用例
hrun
先将YAML/JSON转为pytest(python)格式,然后再运行pytest,所以运行yml文件后会自动在同一目录下生成pytest文件,生成的pytest用例名增加_test
后缀,且.yml/yaml/.json
替换为.py
以后可以直接通过pytest命令执行.py格式的测试用例,hrun
也可以直接使用pytest的参数,比如hrun -sv login.yml
,以下示例是上文中参数化示例执行后生成的.py文件内容
import pytest
from httprunner import Parameters
from httprunner import HttpRunner, Config, Step, RunRequest, RunTestCase
class TestCaseLogin(HttpRunner):
@pytest.mark.parametrize(
"param",
Parameters(
{
"username-password-msg": [
["admin","VCfa……gnw==",None],
["nimda","VCfa……gnw==","用户不存在或者已冻结"],
["admin", "123456", "解密失败,请确认传输加密方式"],
]
}
),
)
def test_start(self, param):
super().test_start(param)
config = Config("登录")
teststeps = [
Step(
RunRequest("获取token")
.post("${ENV(HOST)}/users/login")
.with_headers(**{"SID": "bf5eadddf8eb496bb7788474f8322c6e"})
.with_json({"username": "$username", "password": "$password"})
.validate()
.assert_equal("body.message", "$msg")
.assert_equal("body.message", "$msg")
.assert_equal("body.message", "$msg")
),
]
if __name__ == "__main__":
TestCaseLogin().test_start()
由于httprunner集成了pytest,所以可使用pytest-html
和allure-pytest
报告,pytest-html是内置html报告,可直接使用
hrun testcases --html=report.html # 生成pytest-html格式的报告
allure-pytest需要单独安装pip install allure-pytest
hrun testcases --alluredir=/report/allure # 生成中间结果
allure serve /report/allure # 在线打开报告
allure generate report/allure -o report/allure/html # 生成html报告
locust详细使用方法后续单独开篇,此处简单介绍一下,命令为locusts -f file.py
,使用-f指定YAML/JSON
格式的测试用例时,会首先转换为pytest,然后运行负载测试,所以可以直接压测测试接口时已自动生成的.py格式的文件,下图为压测结果的部分截图
对于没有详细接口文档,需要抓包进行测试的接口,可以通过导出har文件然后转为YAML格式进行测试,Charles和Fiddler都可以导出,如下图所示,使用Fiddler导出时,需注意接口所使用的协议版本
可以使用命令har2case
将HAR文件转成测试用例
har2case login.har # 默认转为json格式
har2case login.har -2y # -2y表示转为yaml格式
下面是转换为yaml格式的内容,通常是需要修改的,比如:断言,关联关系、参数化等都是需要修改完善的
config:
name: testcase description
variables: {}
teststeps:
- name: /user/doLogin
request:
data:
pwd: '123456'
user: admin
headers:
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36
(KHTML, like Gecko) Chrome/93.0.4577.63 Safari/537.36
X-Requested-With: XMLHttpRequest
method: POST
url: http://192.166.66.22:8080/user/doLogin
validate:
- eq:
- status_code
- 200
- eq:
- headers.Content-Type
- application/json;charset=UTF-8
- eq:
- content.user_id
- 1
- eq:
- content.state
- ok
- eq:
- content.gotoUrl
- /ucenter
对生成的测试用例进行修改完善后就可以执行测试啦