安装httprunner
pip install httprunner==4.3.5 (注:python3.12.4 运行hrun命令会失败,可以换成3.12.3)
有4个命令
- httprunner -V
- httprunner -h
- hrun xxx 运行yaml/json/pytest, (会内部执行hmake)
- hmake xxx 把yaml、json格式转成pytest测试用例
一个yaml用例结构
config: {}
teststeps: []
由一个config 和 一个teststeps(多个步骤)组成
config中
补充:
export 的写法:export: [token,xxx]
variables写法:variables : {"username":"tom","passowrod":"123456"}
teststeps中:
后面接 列表,然后每一项内容如
- 局部的变量variables优先级大于config中的全局的变量variables
- extract 是用来提取 响应体中的东西的, 如 token: body.token,
- 在本 步骤 中。做断言等,
- or 给下个步骤使用
teststeps中的request
如果用json,不用body,就不用指定content-type,如
headers: {Content-Type: 'application/x-www-form-urlencoded; charset=UTF-8'}
例子
例1:extract 和export 及变量使用
如:想获取响应中数据,需要在一个请求中extract 提取, 然后在全局中 export, 后续使用变量是用 $变量
例2:一个东西被export多次
(如下,登录获取的cookie)
操作举例(跟着写)
基本用法举例
最新地址(后面脚本中不是最新的):
http://121.43.36.83:7081
按照步骤顺序新增后面的文件
1. 新建login.yml, terminal控制台中运行 hrun login.yml, 代码中使用了全局变量variables,
一个步骤中使用了 extract ,提取了 code 和cookies,去断言
- validate中,断言使用了提取的code, 修改其中的validate的期望改成其他的,会运行失败
- config中,export导出了cookies
config:
name: 用户登录
base_url: http://124.223.33.41:7081
verify: False
parameters: []
variables:
username: auto
password: sdfsdfsdf
export: [cookies]
teststeps:
- name: 登录
request :
method: POST
url: /api/mgr/loginReq
params: {}
headers: {Content-Type: 'application/x-www-form-urlencoded; charset=UTF-8'}
cookies: {}
data:
username: $username
password: $password
extract:
retcode: body.retcode
cookies: cookies.sessionid
validate:
- check : $retcode
assert: equals
expect: 0
msg: 'retcode should be 0'
补充,
validate是step中和name同级的。
并且两种方式都是可以获取到响应体的
2. 新建 course_list.yml ,代码中,一个步骤中没有用request,而是用testcase 引用了其他yml
要点: $cookies是 步骤1 login.yml里面导出的
config:
name: 列出课程
base_url: http://124.223.33.41:7081
verify: False
parameters: []
teststeps:
- name: 登录-获取cookie
testcase: login.yml # 引用login.yml中的testcase
- name: 课程列表
variables:
pagenum: 1
pagesize: 20
request:
method: GET
# url: /api/mgr/sq_mgr/?action=list_course&pagenum=$pagenum&pagesize=$pagesize # 也可以把参数写在 params 中
url: /api/mgr/sq_mgr/
params:
action: list_course
pagenum: $pagenum
pagesize: $pagesize
cookies:
sessionid: $cookies # 引用login.yml (导出的)中的cookies
extract:
retcode: body.retcode
validate:
- check : $retcode
assert: equals
expect: 0
msg: 'retcode should be 0'
3. 新建course_add.yml,extact 提取了couseid,并export导出了 couseid, export继续导出了cookies, 比如修改课程yml会用到它们两个)
注:每次新增后,去页面手动删除一下新增的数据
config:
name: 新增课程
base_url: http://124.223.33.41:7081
verify: False
export:
- cookies
- courseid # 导出变量,修改课程的yml 会用到
teststeps:
- name: 登录-获取cookie
testcase: login.yml
- name: 新增课程
request:
method: POST
url: /api/mgr/sq_mgr/
headers: {Content-Type: 'application/x-www-form-urlencoded; charset=UTF-8'}
cookies:
sessionid: $cookies
body:
action: add_course
data: '{"name":"初中化学tk010201","desc":"a初中化学课程","display_idx":"0"}'
extract:
retcode: body.retcode
courseid: body.id
validate:
- check : $retcode
assert: equals
expect: 0
msg: 'retcode should be 0'
新增course_modify.yaml, 里面使用了新增课程 的导出的id
注:每次新增后,去页面手动删除一下新增的数据
config:
name: 修改课程
base_url: http://124.223.33.41:7081
teststeps:
- name: "登录和新增课程"
testcase: course_add.yml
- name: "修改课程"
extract:
retcode: body.retcode
request:
method: PUT
url: /api/mgr/sq_mgr/
headers: {Content-Type: 'application/x-www-form-urlencoded; charset=UTF-8'}
cookies:
sessionid: $cookies
body:
action: modify_course
id: $courseid
newdata: '{"name":"初中化学tk010201修改","desc":"a初中化学课程","display_idx":"0"}'
validate:
- check : $retcode
assert: equals
expect: 0
msg: 'retcode should be 0'
新建course_delete.yml, 里面先用course_add.yml 新增课程,再第二步删除课程
config:
name: 删除课程
base_url: http://124.223.33.41:7081
teststeps:
- name: "登录和新增课程"
testcase: course_add.yml
- name: "删除课程"
extract:
retcode: body.retcode
request:
method: DELETE
url: /api/mgr/sq_mgr/
headers: {Content-Type: 'application/x-www-form-urlencoded; charset=UTF-8'}
cookies:
sessionid: $cookies
body:
action: delete_course
id: $courseid
validate:
- check : $retcode
assert: equals
expect: 0
msg: 'retcode should be 0'
步骤级初始化举例
1. 新建debugtalk.py文件
def hook_setup():
with open('setup.txt', 'w', encoding='utf-8') as f:
f.write('执行初始化')
def hook_teardown():
with open('teardown.txt', 'w', encoding='utf-8') as f:
f.write('执行清理')
新建个login2.yml中,和name同级写setup_hooks 和 teardown_hooks
- name: 登录
setup_hooks: # 前置操作 使用debugtalk.py中的函数, 特别主要不能用[] 的写法
- ${hook_setup()}
teardown_hooks: # 后置操作 使用debugtalk.py中的函数
- ${hook_teardown()}
config:
name: 用户登录
base_url: http://121.43.36.83:7081
verify: False
parameters: []
variables:
username: auto
password: sdfsdfsdf
export: [cookies]
teststeps:
- name: 登录
request :
method: POST
url: /api/mgr/loginReq
params: {}
headers: {Content-Type: 'application/x-www-form-urlencoded; charset=UTF-8'}
cookies: {}
data:
username: $username
password: $password
extract:
retcode: body.retcode
cookies: cookies.sessionid
validate:
- check : $retcode
assert: equals
expect: 0
msg: 'retcode should be 0'
setup_hooks: # 前置操作 使用debugtalk.py中的函数, 特别主要不能用[] 的写法
- ${hook_setup()}
teardown_hooks: # 后置操作 使用debugtalk.py中的函数
- ${hook_teardown()}
再来运行 login.yml文件,就可以执行 debugtlk.py 里面的方法了, 即会生成两个文件。
清除函数传参验证
先这样改一下,用传参的方式。
如下图,修改login.yml, 给函数传递一个变量
(下图说明,可以把已知的 变量传给函数, 或者把整个 响应结果给函数,用$response)
获取响应, 直接 写 $response
总结:初始化和清除(步骤级别的)
定义函数,在debugtalk.py中
使用
例子如下:
可以发现,清除中,但是 用$response似乎又可以
总结: 变量
- config中的全局变量
- teststeps中的局部变量(优先级大于全局的)
- teststeps中extract提取的变量(本步骤的断言中能使用,下个步骤能使用,导出能使用)
- debugtalk.py中,函数返回的变量(两种方式)
- 环境变量,在.env中使用
4 的两种方式如下:
-
单个变量 -
多个变量,但是要写在confifg中才能获取到
5的环境变量:
补充:当请求参数为json字符串时,要这样改
数据驱动
单字段