httprunner V4.3.5 安装与使用
一、Httprunner介绍
1、什么是Httprunner
HttpRunner 是一款面向 HTTP(S) 协议的通用测试框架,只需编写维护一份 YAML/JSON 脚本,即可实现自动化测试、性能测试、线上监控、持续集成等多种测试需求。
核心特征:
- 继承 Requests 的全部特性,轻松实现 HTTP(S) 的各种测试需求
- 测试用例与代码分离,采用YAML/JSON的形式描述测试场景,保障测试用例具备可维护性
- 测试用例支持分层机制,充分实现测试用例的复用
- 测试用例支持参数化和数据驱动机制
- 使用 skip 机制实现对测试用例的分组执行控制
- 支持热加载机制,在文本测试用例中轻松实现复杂的动态计算逻辑
- 基于 HAR 实现接口录制和用例生成功能(har2case)
- 结合 Locust 框架,无需额外的工作即可实现分布式性能测试
- 执行方式采用 CLI 调用,可与 Jenkins 等持续集成工具完结合
- 测试结果统计报告简洁清晰,附带详尽统计信息和日志记录
- 具有可扩展性,便于扩展实现 Web 平台化(HttpRunnerManager)
2、HttprunnerV4版本介绍
- 开发语言:Golang + Python
- 脚本转换工具:HAR/Postman/Swagger/Curl
- 脚本格式类型:YAML/JSON/pytest/gotest
- 脚本执行引擎:Go 自研 + Python pytest
- 接口测试报告:html 自研(Go template) + pytest-html/allure
- 性能测试引擎:Go Boomer
- 运行环境依赖:Go 引擎无需依赖、pytest 引擎依赖 Python 3.7+
- 安装部署方式: curl/wget/pip
v1/v2/v3/v4 版本对比概览:
3、HttprunnerV4版本Go & Python 功能对比
4、Httprunner 与 unittest & pytest 的区别
使用语言和用途:
- Httprunner 是一个面向HTTP(S)协议的通用开源测试框架,支持YAML、JSON等多种格httprunner主要是一个用于接口自动化测试和性能测试的框架,支持HTTP/HTTPS/HTP2/WebSocket/TCP/RPC协议,使用YAML或JSON格式的文件描述测试用例,特别适合接口测试和性能测试。
- unittest是Python自带的测试框架,主要用于编写单元测试,提供测试用例的编写、测试套件的组织、测试执行和断言等基本功能。
- pytest也是一个用于Python的测试框架,可以进行单元测试和功能测试,具有更简洁的语法和灵活的自动发现测试功能,支持参数化测试、测试装饰器和插件机制等。
学习曲线和复杂性:
- httprunner的语法相对简单,测试脚本编写和维护较为容易,适合初学者快速上手。
- unittest的语法相对繁琐,但在Python标准库中集成,无需额外安装,对于熟悉Python的开发者来说,这是一个优势。
- pytest的语法简单易懂,学习曲线较为平缓,支持多种测试方式和插件,可以满足复杂的测试需求。
功能和特性:
- httprunner支持请求参数化、断言和全局变量等功能,提供丰富的测试报告和日志功能。
- unittest提供了测试用例的编写、测试套件的组织、测试执行和断言等基本功能,适合进行单元测试。
- pytest支持参数化测试、fixture、mock等多种功能,可以生成详细的测试报告,支持并发测试,提高测试效率。
优劣势总结:
- httprunner的优势在于其简单的语法和易用性,并支持多协议HTTP(S)/HTP2/WebSocket/TCP/RPC等,即可实现自动化测试、性能测试、线上监控、持续集成等多种测试需求。
- unittest作为Python自带的测试框架,无需额外安装,但语法相对繁琐。它适合进行单元测试,是Python开发者熟悉的选择。
- pytest以其简洁的语法和强大的功能受到开发者的青睐,支持多种测试方式和插件,可以满足复杂的测试需求。劣势在于对于需要大量IO操作的测试可能存在性能瓶颈。
二、安装
1、Httprunner下载
- 1.1、一键安装部署(MAC):
$ bash -c "$(curl -ksSL https://httprunner.com/script/install.sh)"
如报错提示:无权限则使用sudo命令进行安装:
sudo bash -c "$(curl -ksSL https://httprunner.com/script/install.sh)"
- 检查httprunner安装版本:
httprunner -V or hrun -V
出现版本号即安装成功。
- 检查hrp是否安装成功:
hrp -h
出现下图则安装成功
- 1.2、通过pip安装:(通用Mac&Windows):
建议:安装到虚拟环境下,这样可切换使用不同版本的httprunner
pip install httprunner==4.3.5 //指定版本安装,不加默认下载最新
查看版本:
hrun -V or httprunner -V
“V”一定要大写,不然如下图报错:
- 常见报错:You should consider upgrading via the ‘python -m pip install --upgrade pip’ command.
You are using pip version 10.0.0, however version 20.0.0 is availa- 解决方案:
python -m pip install --upgrade pip //更新升级pip
升级后依然下载失败,可能pip源内找不到httprunner(Windows常见),更新pip的镜像源即可:
pip install -i https://pypi.douban.com/simple httprunner //豆瓣镜像源
pip install -i https://pypi.tuna.tsinghua.edu.cn httprunner //清华大学镜像源
2、Hrp下载
1. 下载hrp
安装httprunner V4.3.5后,还无法使用hrp命令行工具,需要下载编译产物,在 GitHub Releases
页面中自行选择版本进行下载:
2. 配置hrp的环境变量:
- Mac:打开终端进入配置
vim ~/.bash_profile //如果使用的是bash shell
vim ~/.zshrc //如果使用的是zsh shell
进入后添加环境变量:(vim:敲“i”->Enter进入编辑),将以下代码添加进环境变量
export PATH="/usr/local/hrp/bin:$PATH" // 该路径 /usr/local/hrp/bin/hrp 为hrp的文件路径
保存并关闭文件。(vim:保存退出=>Esc–>:wq–>Enter 保存并退出)
生效配置:
source ~/.bash_profile
source ~/.zshrc
验证环境变量配置是否成功:
hrp -h or hrp -v
- Windows配置hrp环境变量:
将下载的包解压后的hrp.exe放在C盘httprunner文件目录下(自定义目录)在【我的电脑=>属性=>高级系统设置=>环境变量=>系统变量】,在PAHT下新 增变量:C:\httprunner 确认保存即可。
验证环境变量:
hrp -h or hrp -v
出现版本号 or 出现帮助页面即可,参考以上。
三、快速上手使用
1、创建手脚架项目
- 新增手脚架项目:
使用以下命令新增Httprunner项目并命名为demo:
hrp startproject demo
如下图即新增成功:
打开demo项目如下图:
2、录制生成Har文件
- Charles 录制 HAR 文件:(fiddler & 浏览器开发者模式F12均可抓包导出为har文件)
以下采用 Charles 等抓包工具为例: 抓取接口导出
存为har格式文件:
3、将Har转换成测试用例
- HttpRunner4.3.5将所有的转换功能都集中在 hrp convert 一个指令中。通过执行 hrp convert -h 可以查询该指令的功能简介、用法和各个选项的介绍:
hrp convert --from-har xxx.har //将HAR文件默认转换成转换成Json文件 文件名为xxx_test.json
hrp convert --from-har xxx.har --to-yaml //将HAR文件转换成YAML文件 文件名为xxx_test.yaml
hrp convert --from-har xxx.har --to-json //将HAR文件转换成Json文件 文件名为xxx_test.json
hrp convert --from-harxxx.har --to-pytest //将HAR文件转换成pytest文件 文件名为xxx_test.py
- 注释:执行hrp convert --from-har xxx.har --to-pytest命令,会先将 xxx.har转化成xxx_test.json,然后再将xxx_test.json转化成xxx_test_test.py
- hrp convert 指令支持指定目录输出,–output-dir 后接测试用例的期望输出目录的路径,用于将转换生成的测试用例输出到对应的文件夹:
hrp convert --from-har xxx.har --to-pytest --output-dir demo/cases //输入文件到当前目录下的demo/cases文件夹中
如下:
- 执行测试用例:
**JSON/YAML(/pytes)**类型的测试用例文件,httprunnerV4.3.5使用hrp run 命令执行:
hrp run xxx.json ##执行json测试用例
hrp run xxx.yaml ##执行yaml测试用例
hrp run testcases/ ##执行testcases文件下所有测试用例
pytest文件可通过pytest命令执行改测试用例文件:pytest xxx.py
目前的 HttpRunner 支持运行 pytest 的测试用例进行接口测试。由于 HttpRunner wraps pytest,因此pytest 所有的参数都可以与 hrp 命令一起使用。
4、手工编写测试用例
pytest 、 YAML 和 JSON 格式的测试用例完全等价,包含的信息内容也完全相同,在httprunner中,测试用例组织主要基于三个概念:
- 1测试用例集(testsuite):对应一个YAML/JSON/Python文件,包含单个或多个测试用例文件。通 俗来将,测试用例集就是「一堆」测试用例。对应地,HttpRunner 除了支持指定单个文件来运行某一测试用例,也支持指定多个文件或指定文件夹来运行一整个测试用例集。
- 测试用例(testcase): 对应一个YAML/JSON/Python文件,包含单个或多个测试步骤。
- 测试步骤(teststep): 对应YAML/JSON/Python中 teststeps 下的一个节点,描述单次接口测试 的全部内容,包括发起接口请求、解析响应结果、检验结果等。
pytest 、 YAML 和 JSON 格式的测试用例,用例结构整体结构都包含两部分:
-
config: 每个测试用例都必须有config部分,作为整个测试用例的全局配置项,用于配置用例:
-
teststeps:包含测试步骤相关信息,测试用例存在顺序关系,运行时将从前往后依次运行 各个测试步骤,其中步骤可以引用其他测试用例:
示例:
request.yaml
config:
name: test
variables: {}
verify: false
teststeps:
- name: "test"
request:
method: GET
url: http://127.0.0.1:8080/api/test/
params:
action: list_course
pagenum: "1"
pagesize: "20"
headers:
Accept: application/json, text/plain, */*
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
Connection: keep-alive
Host: 127.0.0.1:8080
Referer: http://127.0.0.1:8080/mgr/test/index.html
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.0.0 Safari/537.36
X-CSRFToken: ABjPB9CYXuc0dPy8Wu2hJppDVu1sdhWRrfoWPBM7DimSrMtkHVUAoNAXeWqOIh0d
cookies:
csrftoken: ABjPB9CYXuc0dPy8Wu2hJppDVu1sdhWRrfoWPBM7DimSrMtkHVUAoNAXeWqOIh0d
sessionid: b1g42w3ynatxpphy0fhahpdi7g4pn2vg
extract:
msg: body.msg
cookie: header.cookie
validate:
- check: status_code
assert: equals
expect: 200
msg: assert response status code
- eq: ["body.msg","成功"]
request.py
from httprunner import HttpRunner, Config, Step, RunRequest
class TestCaseRequestsTest(HttpRunner):
config = (
Config("request methods testcase with functions")
)
teststeps = [
Step(
RunRequest("")
.get("http://127.0.0.1:8080/api/test/")
.with_params(**{
"action": "list_course",
"pagenum": 1,
"pagesize": 20
})
.with_headers(**{
"Accept": "application/json, text/plain, */*",
"Accept-Encoding": "gzip, deflate, br",
"Accept-Language": "zh-CN,zh;q=0.9",
"Connection": "keep-alive",
"Host": "127.0.0.1:8080",
"Referer": "http://127.0.0.1:8080/mgr/test/index.html",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.0.0 Safari/537.36",
"X-CSRFToken": "ABjPB9CYXuc0dPy8Wu2hJppDVu1sdhWRrfoWPBM7DimSrMtkHVUAoNAXeWqOIh0d",
})
.with_cookies(**{
"csrftoken": "ABjPB9CYXuc0dPy8Wu2hJppDVu1sdhWRrfoWPBM7DimSrMtkHVUAoNAXeWqOIh0d",
"sessionid": "b1g42w3ynatxpphy0fhahpdi7g4pn2vg"
})
.extract()
.with_jmespath("body.msg", "msg")
.with_jmespath("header.cookie", "cookie")
.validate()
.assert_equal("status_code", 200)
.assert_equal("body.msg", "成功")
)
]
if __name__ == "__main__":
TestCaseRequestsTest().test_start()
四、变量 & 提取 & 断言 & 辅助函数 & 参数化 & 环境变量 & 引用其他用例 & 上传文件等的使用
1、变量(variables)
前言:声明变量和引用是经常用到的,引用变量方式有两种:$var 或 ${var} ,通过关键字variables 定义变量主要在config和step中,这两者的区别如下:
- 在 config 中定义的变量为全局变量的,范围比较大,也就是整个测试用例(testcase)的所有地方都 可以引用;
- 在 step 中定义的变量为局部变量,范围比较小,局限于当前测试步骤(teststep)
示例:
config:
name: '定义变量:base_url、Accept、X-CSRFToken'
variables: {
base_url: http://127.0.0.1:8080/api/test/,
Accept: 'application/json, text/plain, */*',
X-CSRFToken: ABjPB9CYXuc0dPy8Wu2hJppDVu1sdhWRrfoWPBM7DimSrMtkHVUAoNAXeWqOIh0d
}
verify: false
teststeps:
- name: "引用config内的变量"
request:
method: GET
url: $base_url ## 引用config内的base_url
params:
action: list_course
pagenum: "1"
pagesize: "20"
headers:
Accept: ${Accept} ## 引用config内的Accept
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
Connection: keep-alive
Host: 127.0.0.1:8080
Referer: http://127.0.0.1:8080/mgr/test/index.html
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.0.0 Safari/537.36
X-CSRFToken: $X-CSRFToken ## 引用config内的X-CSRFToken
cookies:
csrftoken: ABjPB9CYXuc0dPy8Wu2hJppDVu1sdhWRrfoWPBM7DimSrMtkHVUAoNAXeWqOIh0d
sessionid: b1g42w3ynatxpphy0fhahpdi7g4pn2vg
extract:
msg: body.msg
cookie: header.cookie
validate:
- check: status_code
assert: equals
expect: 200
msg: assert response status code
- eq: ["body.msg","成功"]
注释:config 全局变量和 step局部变量名最好不要相同,当出现相同时,step变量优先级大于config变量。
2、提取(extract)
-
extract:V4支持2种响应结果字段提取方式:
- jmespath 表达式:响应结果为 JSON 结构,采用 jmespath 表达式进行参数提取,参考教程。
- 正则表达式(regex):返回的非JSON 格式,可以用正则表达式(regex) 提取。需要具备一 定的正则知识。
-
extract 提取的对象有5种类型:
- headers:从响应 headers 中提取字段,例如 headers.name
- cookies:从响应 cookies 中提取字段,例如 cookies.Token
- body:从响应 body 中提取字段,例如 body.args.foo1
- status_code:提取响应状态码,例如 200、404
- proto:提取协议类型,例如 “HTTP/2.0”、“HTTP/1.1
示例:
config:
name: "request methods testcase with functions"
variables:
foo1: config_bar1
foo2: config_bar2
expect_foo1: config_bar1
expect_foo2: config_bar2
headers:
User-Agent: ${get_user_agent()}
verify: False
export: ["foo3"]
teststeps:
-
name: '测试提取返回的结果'
variables:
foo1: ${ENV(USERNAME)}
foo2: bar21
sum_v: "${sum_two_int(10000000, 20000000)}"
request:
method: GET
url: $base_url/get
params:
foo1: $foo1
foo2: $foo2
sum_v: $sum_v
extract:
foo3: "body.args.foo3" ## 提取foo3的值,body.args.foo3
validate:
- eq: ["status_code", 200]
- eq: ["body.args.foo1", "debugtalk"]
- eq: ["body.args.sum_v", "30000000"]
- eq: ["body.args.foo2", "bar21"]
-
name: post raw text
variables:
foo1: "bar12"
foo3: "bar32"
request:
method: POST
url: $base_url/post
headers:
Content-Type: "text/plain"
cookies: 35c394b6b97ce682c91bd79aedf2c0a987c6a9d419b47651f8df25268bb883b8b364ff67a1cec3d2d1cef94573
body: "This is expected to be sent back as part of response body: $foo1-$foo2-$foo3."
extract:
Content-Type: headers.Content-Type ## 提取headers内的Content-Type
cookies: headers.cookies ## 提取headers内的cookies
status_code: body.code ## 提取body的返回状态码
foo2: body.args.foo2 ## 提取body内foo2的值
proto: request.method ## 提取请求内的请求方式
validate:
- eq: ["status_code", 200]
- eq: ["body.data", "This is expected to be sent back as part of response body: bar12-$expect_foo2-bar32."]
3、断言(validate)
断言validate:
使用jmespath提取 JSON 响应正文(text/html 格式用正则表达式提取)并使用预期值进行验证。
- 提取结果:jmespath 表达式或正则表达式提取,更多细节参考JMESPath 教程
- 预期值:这里也可以使用指定的预期值、变量或函数引用
示例:
config:
name: "request methods testcase with functions"
variables:
foo1: config_bar1
foo2: config_bar2
expect_foo1: config_bar1
expect_foo2: config_bar2
headers:
User-Agent: ${get_user_agent()}
verify: False
export: ["foo3"]
teststeps:
-
name: '断言方式'
variables:
foo1: ${ENV(USERNAME)}
foo2: bar21
sum_v: "${sum_two_int(10000000, 20000000)}"
request:
method: GET
url: $base_url/get
params:
foo1: $foo1
foo2: $foo2
sum_v: $sum_v
extract:
foo3: "body.args.foo3" ## 提取foo3的值,body.args.foo3
# validate: ## 这种方式也可进行断言
# - check: status_code
# assert: equals
# expect: 200
# msg: assert response status code
# - check: headers."Content-Type"
# assert: equals
# expect: application/json;charset=UTF-8
# msg: assert response header Content-Type
validate: ##常用方式
- eq: ["status_code", 200]
- eq: ["body.args.foo1", "debugtalk"]
- eq: ["body.args.sum_v", "30000000"]
- eq: ["body.args.foo2", "bar21"]
断言方式:
4、辅助函数(debugtalk)
前言:v4支持go语言和Python语言写辅助函数,在根目录编辑debugtalk.py文件写辅助函数实现自动化生成动态参数:(主要最后三种方法:账号密码参数化、随机数、时间戳)
import datetime
import logging
import time
from typing import List
import string
import random
def get_user_agent():
return "PpStore/10.7.5(client/phone; iOS 17.5.1; iPhone13,1)"
def sleep(n_secs):
time.sleep(n_secs)
def sum(*args):
result = 0
for arg in args:
result += arg
return result
def sum_ints(*args: List[int]) -> int:
result = 0
for arg in args:
result += arg
return result
def sum_two_int(a: int, b: int) -> int:
return a + b
def sum_two_string(a: str, b: str) -> str:
return a + b
def sum_strings(*args: List[str]) -> str:
result = ""
for arg in args:
result += arg
return result
def concatenate(*args: List[str]) -> str:
result = ""
for arg in args:
result += str(arg)
return result
def setup_hook_example(name):
logging.warning("setup_hook_example")
return f"setup_hook_example: {name}"
def teardown_hook_example(name):
logging.warning("teardown_hook_example")
return f"teardown_hook_example: {name}"
def get_username_password():
"""账号密码参数化"""
return [
{"username": "admin1", "password": "123334"},
{"username": "admin2", "password": "123444"},
{"username": "admin3", "password": "123555"},
{"username": "admin4", "password": "123666"}
]
def generate_random_string(length):
"""随机数"""
letters = string.ascii_letters + string.digits + "!@#$%^&*()"
return ''.join(random.choice(letters) for _ in range(length))
def get_timestamp():
"""时间戳"""
print("timetap", str(int(datetime.datetime.now().timestamp() * 1000)))
return str(int(datetime.datetime.now().timestamp() * 1000))
实例引用debugtalk辅助函数:与引用变量发法一致,如下:get_user_agent()、get_timestamp()
config:
name: "request methods testcase with functions"
variables:
foo1: config_bar1
foo2: config_bar2
expect_foo1: config_bar1
expect_foo2: config_bar2
headers:
User-Agent: ${get_user_agent()} # 引用获取debugtalk函数内的get_user_agent()方法
verify: False
export: ["foo3"]
teststeps:
-
name: '引用辅助函数debugtalk'
variables:
foo1: ${ENV(USERNAME)}
foo2: bar21
sum_v: "${sum_two_int(10000000, 20000000)}"
request:
method: GET
url: $base_url/get
params:
timestamps: $get_timestamp() #引用获取debugtalk函数内的get_timestamp()方法
foo1: $foo1
foo2: $foo2
sum_v: $sum_v
extract:
foo3: "body.args.foo3" ## 提取foo3的值,body.args.foo3
validate: ##常用方式
- eq: ["status_code", 200]
- eq: ["body.args.foo1", "debugtalk"]
- eq: ["body.args.sum_v", "30000000"]
- eq: ["body.args.foo2", "bar21"]
5、参数化(parameters)
前言:实现参数化使用parameters关键字,数据源有三种方式:
- 在 yaml 文件中直接写测试数据源,最为简单,适合参例表比较少的场景。
- 测试数据源写到 csv 文件,该种方式需要准备 CSV 数据文件,适合数据量比较大的情况。
- 自定义函数,函数返回列表形式数据,该种方式最为灵活,可通过自定义 Python 函数实现任意场景的数据驱动机制,当需要动态生成参数列表时也需要选择该种方式。
单个参数进行参数化:
config:
name: "request methods testcase with functions"
verify: False
export: ["foo3"]
parameters:
foo1: [123456, 1234567, 12345678, 123456789]
foo2: [111111, 22222222, 3333333, 444444444]
teststeps:
-
name: 'parameters参数化-单个'
variables:
sum_v: "${sum_two_int(10000000, 20000000)}"
request:
method: GET
url: $base_url/get
params:
timestamps: $get_timestamp() #引用获取debugtalk函数内的get_timestamp()方法
foo1: ${foo1}
foo2: $foo2
sum_v: $sum_v
extract:
foo3: "body.args.foo3" ## 提取foo3的值,body.args.foo3
validate: ##常用方式
- eq: ["status_code", 200]
- eq: ["body.args.foo1", "debugtalk"]
- eq: ["body.args.sum_v", "30000000"]
- eq: ["body.args.foo2", "bar21"]
以上执行后会生成4条case。
关联性参数化:
config:
name: "request methods testcase with functions"
verify: False
export: ["foo3"]
parameters:
foo1-foo2: # 关联性参数
- [123456, 111111]
- [1234567, 22222222]
- [12345678, 3333333]
- [123456789, 444444444]
# foo1: [123456, 1234567, 12345678, 123456789]
# foo2: [111111, 22222222, 3333333, 444444444]
teststeps:
-
name: 'parameters参数化-关联性参数'
variables:
sum_v: "${sum_two_int(10000000, 20000000)}"
request:
method: GET
url: $base_url/get
params:
timestamps: $get_timestamp() #引用获取debugtalk函数内的get_timestamp()方法
foo1: ${foo1}
foo2: $foo2
sum_v: $sum_v
extract:
foo3: "body.args.foo3" ## 提取foo3的值,body.args.foo3
validate: ##常用方式
- eq: ["status_code", 200]
- eq: ["body.args.foo1", "debugtalk"]
- eq: ["body.args.sum_v", "30000000"]
- eq: ["body.args.foo2", "bar21"]
关联性参数常用于账号密码:
###几组账号密码中,如果不同账号对应不同密码,这时候就得用关联性参数化了:
config:
name: '关联性参数化-常用于账号密码--与笛卡尔积组合一至'
parameters:
username-password:
- [ admin1, "123334" ]
- [ admin2, "123444" ]
- [ admin3, "123555" ]
- [ admin4, "123666" ]
teststeps:
-
name: '关联性参数化-常用于账号密码--与笛卡尔积组合一至'
request:
method: POST
url: ${ENV(base_url_test)}/login
params:
username: ${username}
password: $password
validate:
- eq: [status_code, 200]
- eq: [headers."Content-Type", "application/json"]
笛卡尔积组合:
假如测试用例中定义了多个参数,那么测试用例在运行时会对参数进行笛卡尔积组合,覆盖所有参数组合情况。
- 账号有4种[admin1, admin2, admin3, admin4],
- 密码有4种 [“123456”, “123456”, “123456”, “123456”]
- 用笛卡尔积组合的话,就是4*4=16种组合
###几组账号密码中,如果不同账号对应不同密码,这时候就得用关联性参数化了:
config:
name: '笛卡尔积参数化组合'
parameters:
username-password:
- [ admin1, "123334" ]
- [ admin2, "123444" ]
- [ admin3, "123555" ]
- [ admin4, "123666" ]
teststeps:
-
name: '笛卡尔积参数化组合'
request:
method: POST
url: ${ENV(base_url_test)}/login
params:
username: $username
password: ${password}
validate:
- eq: [status_code, 200]
- eq: [headers."Content-Type", "application/json"]
CSV文件:对于 CSV 数据源文件,需要遵循如下几项约定的规则:
- CSV 文件中的第一行必须为参数名称,从第二行开始为参数值,每个(组)值占一行;
- 若同一个 CSV 文件中具有多个参数,则参数名称和数值的间隔符需实用英文逗号;
- 在 YAML/JSON 文件引用 CSV 文件时,文件路径为基于项目根目录(debugtalk.py 所在路径)的相对路径。
示例:
test_data.csv
username,password
admin1,123334
admin2,123444
admin3,123555
admin4,123666
引用csv文件:
###几组账号密码中,如果不同账号对应不同密码,这时候就得用关联性参数化了:
config:
name: 'csv文件参数化案例'
parameters:
username-password: ${P(data/test_data.csv)}
teststeps:
-
name: 'csv文件参数化案例'
request:
method: POST
url: ${ENV(base_url_test)}/login
params:
username: $username
password: ${password}
validate:
- eq: [status_code, 200]
- eq: [headers."Content-Type", "application/json"]
外部函数(debugtalk)参数化:用 debugtalk.py 中自定义的函数生成参数列表,生成的参数列表必须为 list of dict 的数据结构:
需对 username、password 进行参数化数据驱动,那么就可以在 debugtalk.py 中定义一个函数,返回参数列表。
debugtalk.py
def get_username_password():
"""账号密码参数化"""
return [
{"username": "admin1", "password": "123334"},
{"username": "admin2", "password": "123444"},
{"username": "admin3", "password": "123555"},
{"username": "admin4", "password": "123666"}
]
示例:
config:
name: 'debugtalk辅助函数参数化'
parameters:
username-password: $(get_username_password())
teststeps:
-
name: 'debugtalk辅助函数参数化'
request:
method: POST
url: ${ENV(base_url_test)}/login
params:
username: $username
password: ${password}
validate:
- eq: [status_code, 200]
- eq: [headers."Content-Type", "application/json"]
6、环境变量(.env)
在前面最初新建httprunner项目后,在根目录下自动生成.env文件,V4版本中内置了函数 ENV 读取环境变量的值,可直接使用${ENV(key)}进行引用。
.env
base_url_test=http://127.0.0.1:8080/api/test/
USERNAME=admin
PASSWORD=123456
引用:
config:
name: '引用.env环境变量内的值'
teststeps:
-
name: '测试引用.env环境变量内的值'
request:
method: POST
url: ${ENV(base_url_test)}/login
params:
username: ${ENV(username)}
password: ${ENV(password)}
validate:
- eq: [status_code, 200]
- eq: [headers."Content-Type", "application/json"]
7、引用其他用例
示例:
config:
name: '引用其他用例'
variables: {}
verify: False
teststeps:
- name: '引用login接口用例'
- testcase: testcases/login.yaml #引用login用例:login用例存放的路径
- name: '引用login接口用例'
request:
method: POST
url: ${ENV(base_url_test)}/getList
headers:
Accept: application/json, text/plain, */*
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
Connection: keep-alive
Host: 127.0.0.1:8080
validate:
- eq: [status_code, 200]
- eq: [headers."Content-Type", "application/json"]
8、上传文件
upload文件上传:需要2个依赖包(requests_toolbelt 、 filetype)
pip install requests_toolbelt
pip install filetype
pip install requests_toolbelt filetype #两个依赖包一起下载
示例:
config:
name: '上传文件'
variables: {}
verify: False
teststeps:
- name: '上传文件upload file'
request:
method: POST
url: ${ENV(base_url_test)}/upload
upload:
file: data/test_photo.png #文件路径
title: "上传图片"
validate:
- eq: [status_code, 200]
- eq: [headers."Content-Type", "application/json"]
五、测试报告
1、原生测试报告
V4.3.5版本自带原生的html测试报告,可通过 hrp run -h 得知:hrp run <用例> -g
(不管在那个目录下运行,同一根目录会生成results文件件)
查看生成报告的命令:hrp run -h
执行命令:
hrp run <测试用例> -g
使用浏览器打开report.html
以上报告不美观,信息不完整,难以一眼看出执行情况。
pytest同时也自带html报告,执行一下命令生成pytest的测试报告:
pytest -html=results/results.html # 等号后面为报告存放的路径
如下图pytest报告,也不美观,无统计。
2、Allure测试报告
Allure报告美观大气,一眼看出执行情况及返回报文均为json格式。
2.1、下载Allure
- 下载安装Allure;
- 配置环境变量(参考Windows&Mac);
- 验证环境变量是否配置成功: allure --version 显示版本信息则配置成功;
- 在Python中下载allure-pytest插件:pip install allure-pytest ;
3、Allure的使用
- 执行用例并生成报告:
pytest <用例> -s -q --alluredir ./results --clean-alluredir ##存放路径,--clean-alluredir清空历史数据
运行后可以看到生成了txt,json等格式的文件,还未生成HTML格式:
接着执行:
allure generate report/ -o results/html --clean
执行后,生成html文件下的index.html
打开index.html文件如下图:
六、其他(敬请期待)
1、将测试报告发送邮件及发送到群聊-Done
2、Httprunner4.3.5+Locust+Grafana实现性能监控-ing
希望上文对您有所帮助,遇到问题欢迎留言,有空都会回复的,谢谢大家!
创作不易,你的鼓励将是我创作的最大动力。。。