httprunner4.x使用(含代码)
1.运用脚手架创建项目
进入项目路径,运行命令,新增一个Httprunner项目
hrp startproject demotest
运行完成,在目录下可看到如下文件
各文件意义如下(demo就是demotest,只是名称不一样)
脚手架项目有几个有效的测试用例,可以直接编辑直接执行命令 hrp run demotest运行,若命令运行成功,说明Python版本及Httprunner依赖包没有冲突,可正常使用。
2.测试用例有录制的用例和手工编写的用例两种方法
方法(1)录制生成用例
步骤1,导出har文件
通过fiddler/Charles等抓包工具进行抓包,生成har文件(charles导入)
Charles导出会更好用一些
fiddler点击File--Export Sessions--Selected Sessions,选择Httparchive v1.2格式,导出文件到项目目录的 har 文件
步骤2,转化为测试用例文件
httprunner4.x将所有转换功能都集中在 hrp convert一个指令中,通过执行 hrp conver -h可以查询该功能指令的简介和用法。
除了转换成JSON/YAML/pytest类型的文件,Httprunner4.x还支持将HAR包转换成gotest测试用例
执行hrp convert xxx.har --to-pytest命令,会先将xxx.har文件转换成 xxx_test.json文件,然后再将xxx_test.json转化成xxx_test_test.py文件。
hrp convert支持指定目录输出,--output-dir后接测试用例期望输出的目录路径,用于将转换生成的测试用例输出到对应的文件夹中
hrp convert fidd.har --to-pytest --output-dir ./cases 输出文件到当前目录下cases文件
测试时如果报错WRN skip file expectExtensions=[".json"] path=***.har)
查询了各种原因,根据hrp conver -h查询到的,可能出现在指令问题上
尝试修改指令后,成功!!!!!!!!!!!!!!
hrp convert --from-har C:\study\httprunner\hruns\demotest\har\fidd.har
在文件夹中可看到生成的json文件
同理,转换成pytest文件
hrp convert --from-har C:\study\httprunner\hruns\demotest\har\jen.har --to-pytest --output-dir C:\study\httprunner\hruns\demotest\testcases
执行命令后,生成json和py文件,如下图
步骤3.执行测试用例
httprunner3.x用hrun命令执行,httprunner4.x用 hrp run命令执行
Httprunner4.x也可以用hrun命令执行测试用例文件,但hrp控制台打印日志比较详细,而且hrp可以执行文件夹中的所有测试用例
hrp run jen_test_test.py
执行测试用例同时生成测试报告,通过hrp run -h可知为 hrp run 文件 -g
进入项目下执行指令(不管在哪个路径下运行,同一根目录下会生成results文件夹)
hrp run jen_test_test.py -g
运行后,results文件夹里面内含报告
文件html 打开后显示如下
allure报告(安装allure)
https://blog.csdn.net/seanyang_/article/details/129195363
方法(2)手工编写测试用例
1.
在httprunner中,测试用例组织主要基于三个概念:
测试用例集(testsuite):对应一个YAML/JSON/Python文件,包含单个或多个测试用例文件。通俗来将,测试用例集就是「一堆」测试用例。对应地,HttpRunner 除了支持指定单个文件来运行某一测试用例,也支持指定多个文件或指定文件夹来运行一整个测试用例集
测试用例(testcase):对应一个YAML/JSON/Python文件,包含单个或多个测试步骤。
测试步骤(teststep):对应YAML/JSON/Python中 teststeps 下的一个节点,描述单次接口测试的全部内容,包括发起接口请求、解析响应结果、检验结果等。
YAML/json/pytest结构的测试用例,用例整体结构都包含两部分
config:每个测试用例都包含config部分,作为整个测试用例的全局配置项,用于配置用例
teststep:包含测试步骤相关信息,测试用例存在顺序关系,运行时从前往后依次运行各个测试步骤,其中测试步骤可以引用其他测试用例
用例配置项(config)名称 | 含义 |
name(必填) | 用例名称描述,在log和报告中显示 |
verify(非必填) | 客户端是否进行SSL校验(todo) |
base_url(非必填) | 测试用例中的通用HOST,例如http://httprunner.com,若base_url被绑定,测试步骤中的url只能写相对路径 |
headers(非必填) | 定义测试用例级别的请求头 |
environs(非必填) | 配置环境变量(若未指定,则会从.env文件导入) |
variable(非必填) | 定义为全局变量,作用域为整个用例,每个测试步骤都可以引用config variables.测试步骤中step variables优先级别高于config varaibles |
parameters(非必填) | 全局参数,用于实现数据化驱动,作用域为整个用例 |
parameters_setting(非必填) | 配置参数驱动的具体策略 |
think_time(非必填) | 配置思考时间的具体策略、超时时间限制等 |
websocket(非必填) | 配置websocket断开重连的最大次数和间隔等(todo) |
export(非必填) | 导出当前测试用例中的变量 |
weight(非必填) | 性能测试中,分配给当前测试用例的虚拟用户权重 |
path(非必填) | 当前测试用例所在路径(通常不需要手工填写) |
测试步骤类型 | 含义 | 适用的测试步骤 |
name(必填) | 用例名称描述,在log和报告中显示 | |
request(必填) |
用于发起HTTP请求的步骤类型,包含method/url/params/headers/cookie等请求信息 (method和url必填) HTTP的请求方式有GET、POST、HEAD、PUT、DELETE、CONNECT、OPTIONS、TRACE、PATCH,比较常用的请求方式是POST和GET |
|
api(非必填) | 用于引用API的步骤类型 | |
testcase(非必填) | 用于引用其他测试用例的步骤类型 | |
transaction(非必填) | 用于定义一个事务 | |
rendezvous(非必填) | 集合点 | |
think_time(非必填) | 思考时间 | |
WebSocket(非必填) | 用于发起WebSocket请求的步骤类型 | |
variables(非必填) | 局部变量 | 通用 |
setup_hook(非必填) | 前置函数 | request/api/websocket |
teardown_hook(非必填) | 后置函数 | request/api/websocket |
extract(非必填) | 变量提取。参数提取格式,变量名:body.属性名,指从响应体body里提取属性的值 | request/api/websocket |
validate(非必填) | 结果校验 | request/api/websocket |
export(非必填) | 导出变量 | testcase |
代码部分
1213.yaml
config: name: classinfo variables: {} verify: false teststeps: - name: "getclass" request: method: GET url: http://127.0.0.1:8080/api/mgr/sq_mgr/ 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/ps/mgr/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.Set-Cookie validate: - check: status_code assert: equals expect: 200 msg: assert response status code - eq: ["body.msg","成功"]
转化为pytest文件
hrp convert --from-yaml C:\study\httprunner\yaml\1213.yml --to-pytest --output-dir C:\study\httprunner\yaml
运行后生成文件T1213_test_test.py
# NOTE: Generated By HttpRunner v4.3.5 # FROM: 1213_test.json from httprunner import HttpRunner, Config, Step, RunRequest class TestCaseT1213Test(HttpRunner): config = Config("classinfo") teststeps = [ Step( RunRequest("getclass") .get("http://127.0.0.1:8080/api/mgr/sq_mgr/") .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/ps/mgr/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("header.Set-Cookie", "cookie") .with_jmespath("body.msg", "msg") .validate() .assert_equal("status_code", 200, "assert response status code") .assert_equal("body.msg", "成功") ), ] if __name__ == "__main__": TestCaseT1213Test().test_start()
11.json
{ "config": { "name": "classinfo" }, "teststeps": [ { "name": "getclass", "request": { "method": "GET", "url": "http://127.0.0.1:8080/api/mgr/sq_mgr/", "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/ps/mgr/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", "sec-ch-ua-platform": "\"Windows\"" }, "cookies": { "csrftoken": "ABjPB9CYXuc0dPy8Wu2hJppDVu1sdhWRrfoWPBM7DimSrMtkHVUAoNAXeWqOIh0d", "sessionid": "b1g42w3ynatxpphy0fhahpdi7g4pn2vg" } }, "validate": [ { "check": "status_code", "assert": "equals", "expect": 200, "msg": "assert response status code" }, { "check": "body.msg", "assert": "equals", "expect": "成功", "msg": "assert response body msg" } ] } ] }
转化为pytest文件
hrp convert --from-json C:\study\httprunner\json\11.json --to-pytest --output-dir C:\study\httprunner\json
运行后生成文件T11_test_test.py
# NOTE: Generated By HttpRunner v4.3.5 # FROM: 11_test.json from httprunner import HttpRunner, Config, Step, RunRequest class TestCaseT11Test(HttpRunner): # 11为原json文件的文件名 config = Config("classinfo") teststeps = [ Step( RunRequest("getclass") .get("http://127.0.0.1:8080/api/mgr/sq_mgr/") .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/ps/mgr/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", "sec-ch-ua-platform": '"Windows"', } ) .with_cookies( **{ "csrftoken": "ABjPB9CYXuc0dPy8Wu2hJppDVu1sdhWRrfoWPBM7DimSrMtkHVUAoNAXeWqOIh0d", "sessionid": "b1g42w3ynatxpphy0fhahpdi7g4pn2vg", } ) .validate() .assert_equal("status_code", 200, "assert response status code") .assert_equal("body.msg", "成功", "assert response body msg") ), ] if __name__ == "__main__": TestCaseT11Test().test_start()