httprunner
httprunner
(仅作为个人笔记,如有雷同,请联系删除。。)
https://www.cnblogs.com/aichixigua12/p/13162479.html
HttpRunner 是一款面向 HTTP(S) 协议的通用测试框架,只需编写维护一份 YAML/JSON
脚本,即可实现自动化测试、性能测试、线上监控、持续集成等多种测试需求。
1、特点:
- 继承 Requests 的全部特性,轻松实现 HTTP(S) 的各种测试需求
- 采用
YAML/JSON
的形式描述测试场景,保障测试用例描述的统一性和可维护性 - 借助辅助函数(debugtalk.py),在测试脚本中轻松实现复杂的动态计算逻辑
- 支持完善的测试用例分层机制,充分实现测试用例的复用
- 测试前后支持完善的 hook 机制
- 响应结果支持丰富的校验机制
- 基于 HAR 实现接口录制和用例生成功能(har2case)
- 结合 Locust 框架,无需额外的工作即可实现分布式性能测试
- 执行方式采用 CLI 调用,可与 Jenkins 等持续集成工具完美结合
- 测试结果统计报告简洁清晰,附带详尽统计信息和日志记录
- 极强的可扩展性,轻松实现二次开发和 Web 平台化
2、安装:
pip install httprunner
,安装完成后cmd命令检查:hrun -V
可以用相关命令直接生成对应的项目文件夹:hrun –startproject 文件夹(如HttpRunnerDemo)
,执行命令后可以看到生成对应的目录,在当前目录下。
报错解决:原因是框架的版本升级了。
解决方案:去掉– ,直接用 httprunner startproject HttpRunnerDemo
来创建项目。(hrun不好使)
文件目录结构说明:
(1). YAML/JSON:(必须)测试用例文件,一个文件对应一条测试用例。
(2). debugtalk:(可选)脚本函数,存储项目中逻辑运算函数,该文件存在时,将作为项目定位标记,其所在目录被视为项目工程的根路径,该文件不存在时,运行测试的路径将被视为当前工作目录,测试用例文件中的相对路径,如.csv均需基于当前工作目录,运行测试后,测试报告文件夹reports会生成在当前工作目录
(3). .env:(可选)存储项目环境变量
(4). reports、logs:(自动生成)运行后自动生成,无需创建
3、YAML文件:作为测试脚本文件。
YAML文件可以创建为.yml文件,.yml需遵循严格的缩进。
-
基本语法:
(1). 格式要求:K:(空格) v,表示一对键值对,必须要写空格,#表示注释
(2). 以空格的缩进来控制层级关系,只要是左对齐的一列数据,都是同一个层级的
(3). 属性和值大小写敏感
(4). 缩进不能用tab键,手动空格 -
注意:
(1). 对于单个YAML/JSON文件来说,数据存储结构为 list of dict的形式,其中可能包含一个全局配置项(config)和若干个测试步骤(test);
(2). HttpRunner划分了两层变量空间作用域(context)-
config:作为整个测试用例的全局配置项;
-
test:测试步骤的变量空间(context)会继承或覆盖config中定义的内容
注意:若某变量在config中定义了,在某test中没有定义,则该test会继承该变量;若某变量在config和test中都定义了,则该test使用config中定义的变量值,各个测试步骤的变量空间相互堵路,互不影响,如需在多个测试步骤中传递参数值,则需要使用extract关键字,并且只能从前往后传递
eg:在testcases中建立一个demo的yml文件,把接口测试资料按一定的规则写入:
注:config中引入的变量:很多接口的公共部分,可以抽离出来放入debugtalk.py
- config: # config是接口配置部分 request: headers: $content # 在config中引入变量$host、$content等 base_url: $host url: /commons_service/weather/getWeatherListByLocation?appType=6&requestId=777777 method: POST - test: # test是用例部分 name: test weather ID1 request: json: body: {"lat":"", "lng":"", "city":"武汉市"} validate: # validate是断言部分 - eq: [status_code,200] - eq: [json.msg,"成功"] - test: name: test weather ID2 request: json: body: { "lat":"123","lng":"125","city":""} validate: - eq: [status_code,200] - eq: [json.msg,"成功"]
-
4、运行case:
hrun HttpRunnerDemo\testcases\demo_testcase_ref.yml
另还会在logs下生成测试日志: HttpRunnerDemo\logs\77343183-2374-4d6a-a499-6580fbb89b45.run.log
,可以打开log查看详情,可以清晰的看到接口返回和断言结果。
注意:感觉是在运行时会把yaml测试文件转换成对应的_test.py文件,可以关注下。
5、httprunner还支持接口录制
(用抓包工具生成.har文件)后转为可执行的用例(用har2case),最重要的是,测试用例和代码的分离。这样使得稍有编码功底的人迅速上手。
6、简单的接口测试场景:
利用HttpRunner发送请求–(get/post,带参数/不带参数)
eg:伪代码,不执行
### 1.get请求,不带参数,并对响应结果正则表达式提取做断言
- config:
name: "get请求,不带参数"
base_url: http://www.baidu.com
- test:
name: "open xxx.."
request:
url: /okhll/
method: GET
extract:
- code: "status_code"
- title: 'tid=72872&fid="89" class="st" style="" title="测试">(.+?)</a>'
validate:
- eq: [$code, 200]
- eq: [$title, '测试']
### 2.get请求,带参数
- config:
name: "get请求,带参数"
base_url: http://www.baidu.com
- test:
name: "get access_token"
request:
url: /cgi_bin/token
method: GET
params:
grant_type: 'clcoxxxxxxxxxsla'
appid: 'wk9jh92m83'
secret: 'a5d68699c76d986b766e282367378c7627c6c7'
extract:
- access_token: content.access_token
validate:
- eq: ["status_code", 200]
- eq: [content.expires_in, 7200]
### 3.模拟请求头
- config:
name: "发送模拟请求头的请求"
base_url: "https://www.baidu.com"
- test:
name: 请求的对象是百度
request:
url: /
method: GET
headers:
Accept: */*
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7
User-Agetn: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36
validate:
- eq: [status_code, 200]
### 4.post请求
- config:
name: 发送post请求
basr_url: https://www.baidu.com
- test:
name: 发送post请求
request:
url: /cgi-bin/tags/create
method: POST
params:
access_token: $access_token
json: {
"open_id": "kshdu7236n1928n17631mh",
"remark": "luoks"
}
validate:
- eq: ['status_code', 200]
7、参数说明:
-
config参数:
(1). output的用法(也可以用export代替):其作用是输出值,相当于print()函数的输出功能,另一个作用则是可以定义变量时用,经常与extract关键字一起组合使用- config: name: "访问百度首页" base_url: www.baidu.com output: - code - title - test: name: "open baidu first-page" request: url: /phpuwk/ method: GET extract: - code: "status_code" - title: 'tid=72872&fid="89" class="st" style="" title="测试">(.+?)</a>' validate: ...
-
test参数:
(1). extract关键字:可以提取的关键字为:
status_code, cookies, elapsed, headers, content, text, json, encoding, ok, reason, url
。支持多种提取方式:- 响应结果为 JSON 结构:可采用==.运算符==的方式,例如
headers.Content-Type、content.success
- 响应结果为 text/html 结构:可采用正则表达式的方式,例如
blog-motto\">(.*)
(2). request 关键词:包括http请求中的详细内容
- headers:请求头部信息
- method: 请求方式
- url:请求地址
- host:请求主机地址
- params:GET请求参数
- data:表单形式的参数
- json:json格式的参数
- 响应结果为 JSON 结构:可采用==.运算符==的方式,例如
8、断言:
-
validate关键字:拿实际结果和期望结果去比较。支持两种格式:
(1).{"comparator_name": [check_itrm, expect_value]}
(2).{'check': check_itrm, 'comparator': comparator_name, 'expect': expect_value}
举例:- config: name: "get请求,不带参数" base_url: http://www.baidu.com - test: name: "open xxx.." request: url: /okhll/ method: GET validate: - {'check': status_code, 'comparator': eq, 'expect': 200}
-
contains关键字:判断包含的断言。
-
使用:
- contains: [content, 响应正文中的值]
,判断响应正文中是否包含了某字符串 -
举例:
- config: name: "get请求,带参数" base_url: http://www.baidu.com - test: name: "get access_token" request: url: /cgi_bin/token method: GET params: grant_type: 'clcoxxxxxxxxxsla' appid: 'wk9jh92m83' secret: 'a5d68699c76d986b766e282367378c7627c6c7' extract: - access_token: content.access_token validate: - contains: [content, access_token]
-
9、变量的创建及使用:
- 定义变量:
variables
关键字定义,export
也会定义变量【一个test中赋值之后,可被其他test通过$引用】 - 使用变量:
$变量名
,如: $name
10、传参操作:
-
test中测试步骤之间传参:
- config: name: "访问xxx" base_url: www.xxx.com export: - token # 2. 控制台输出变量token的值 - test: name: "获取access_token" request: url: /phpuwk/ method: GET params: xxx: xxx extract: - token: content.access_token # 1. extract提取access_token的值,并赋值给变量token validate: ... - test: name: 查看已经被创建的标签 request: url: /okhll/ method: GET headers: content-type: alication/json params: access_token: "$token" # 3. 引用token值 validate: ...
-
.env文件:存放设置的全局变量参数及参数值,引用方式为:
${ENV(参数名)}
## .env url = https://api.weixin.qq.com ## xxx.yml - config: name: "引用.env文件传递参数" base_url: ${ENV(url)} ...
-
debugtalk.py文件:可在这个文件中编写辅助函数,然后进行关联。引用该文件中的函数的方法为:
${函数名}
## debugtalk.py #! /usr/bin/env_python # encoding: utf-8 import requests def get_token(): get_data={"grant_type":"xxx", "appid":"xxx", "secret":"xxxxxxx"} respone = requests.get(url='https://api.weixin.qq.com/cgi-bin/token', params=get_data) return respone.json()['access_token'] ## xxx.yml ... - test: name: "引用debugtalk.py文件函数传递参数" request: url: /cgi-bin/tags/get method: GET headers: content-type: alication/json params: access_token: ${get_token()} ## 引用debugtalk.py文件函数传递参数 validate: ...
-
用例之间传参:把需要的值都给参数化,然后进行相互调用,可以提高代码复用率
举例:【注意:这几个过程中,变量名必须保持一致】
(1). 先在test中用extrac关键字提取出token赋值给token_id;
(2). 然后config中用export关键字输出token_id值;
(3). 其他test需要引用的情况下,需要先使用variables关键字定义该变量然后再引用## test1.yaml - config: name: "访问xxx" base_url: www.xxx.com export: - token_id # 2. 控制台输出token_id - test: name: "获取access_token" request: url: /phpuwk/ method: GET params: xxx: xxx extract: - token_id: content.access_token # 1. 提取并赋值access_token给token_id validate: ... ## test2.yaml - config: name: "get请求,带参数" base_url: ${ENV(url)} - test: name: "调用获取access_token的接口,引用其中的access_token参数" testcase: testcases/test1.yaml # 执行test1.yaml,方便引用其中的access_token参 - test: variables: token_id: $token_id # 3. 定义变量 name: 查看已经被创建的标签 request: url: /okhll/ method: GET headers: content-type: alication/json params: access_token: $token_id # 4. 引用变量 validate: - {'check': status_code, 'comparator': eq, 'expect': 200}
11、参数化:
-
通过testsuite中编写parameter关键字参数化:从2.0.0版本开始,HttpRunner不再支持在测试文件中进行参数化配置,参数化的功能需要在testsuite中实现,实现的方式为parameters下面写参数,testsuite中执行的时候需要引用testcases中的用例,参数化后需要在testsuite中运行yml文件
### testsuit.yml 文件 config: name: 参数化测试套件 testcases: - name: 这里引用testcases中的测试用例 testcase: testcases/test01.yml # ----------> 测试用例的绝对路径 parameters: # ---------------------------> 设置参数 serch_word: [baidu, 777, python] # ------> 参数名:参数列表 ### test01.yml 文件 - config: name: 测试用例,被上面测试套件引用 base_url: https://www.baidu.com export: - title - test: name: 百度搜索 request: url: /s method: GET params: wd: $serch_word # ---------------------> 对testsuit中parameters设置的参数的引用 header: Accept: xxx Accept-Encoding: xxx Accept-Language: xxx User-Agent: xxx extract: - title: <title>(.+?)</title> validate: -eq: ["status_code", 200]
(1). testsuite传递多个参数:以-隔开参数,以列表的方式处理【一个list:是一组参数,传递给多个变量;一个-:case执行一次,所谓参数化】
### testsuit.yml 文件 config: name: 参数化测试套件 #testcases: # - name: 这里引用testcases中的测试用例 # testcase: testcases/test01.yml # ----------> 测试用例的绝对路径 # parameters: # ---------------------------> 设置参数 # serch_word: [baidu, 777, python] # ------> 参数名:参数列表 testcases: - name: 这里引用testcases中的测试用例 times: 5 skipIf: [1, 2] testcase: testcases/test02.yml # ----------> 测试用例的绝对路径 parameters: # ---------------------------> 设置参数 serch_word-result: # --------------> 以-隔开参数,以列表的方式处理:参数1:serch_word,参数2:result - [python, python_百度搜索] # ----------> 第一组参数:[参数1,参数2] - [chrome, chrome_百度搜索] # ----------> 第二组参数 - [google, google_百度搜索] # ----------> 第三组参数 ### test02.yml 文件 - config: name: 测试用例,被上面测试套件引用 base_url: https://www.baidu.com export: - title - test: name: 百度搜索 extract: - title: <title>(.+?)</title> request: url: /s method: GET params: wd: $serch_word # ---------------------> 引用第一个参数:即-的前半部分,serch_word header: Accept: xxx Accept-Encoding: xxx Accept-Language: xxx User-Agent: xxx validate: -eq: [$title, $result] # -----------------> 引用第二个参数:即-的后半部分,result
(2). 笛卡尔积的运用:比如测试账号有四种[“test1”, “test2”, “test3”, “test4”],密码也有四种 [“123456”, “123456”, “123456”, “123456”],用笛卡尔积组合的话,就是4*4=16种组合
### testsuit.yml 文件 config: name: 参数化测试套件 testcases: - name: 这里引用testcases中的测试用例 times: 5 skipIf: [1, 2] testcase: testcases/test02.yml # ----------> 测试用例的绝对路径 parameters: # ---------------------------> 设置参数 user: ["test1", "test2", "test3", "test4"] # passwd: ["123456", "123456", "123456", "123456"] # case中传入$user和$passwd,case会执行16种组合的次数
-
利用csv文件进行参数化:根路径下新建data文件夹–新建info.csv文件,文件中的参数用" , "符号分隔,testsuit中通过P()函数进行引用,case里面需要csv文件中的参数时,则通过 $ 参数名的方法调用,与csv中的参数排列顺序无关,注意参数名称必须与csv表头保持一致
### E:\Code_local\HttpRunnerDemo\data\info.csv search_word,result # 搜索参数,预期结果 taobao,taobao_百度搜索 python,python_百度搜索 123456,123456_百度搜索 charme,charme_百度搜索 google,google_百度搜索 ### testsuit.yml config: name: 参数化测试套件 testcases: - name: 这里引用testcases中的测试用例 testcase: testcases/test02.yml parameters: search_word-result: ${P(data/info.csv)} # 引用csv文件,csv参数的个数通过-隔开 ### test01.yml - config: name: 测试用例,被上面测试套件引用 base_url: https://www.baidu.com export: - title - test: name: 百度搜索 request: url: /s method: GET params: wd: $serch_word # ------------> 引用第一个参数:即-的前半部分,serch_word header: Accept: xxx Accept-Encoding: xxx Accept-Language: xxx User-Agent: xxx extract: - title: <title>(.+?)</title> validate: -eq: [$title, $result]
-
通过debugtalk实现参数化:(相当于jmeter中的函数助手的功能),与parameters下引用csv一样,debugtalk参数化的数据也是一个列表,使用
${函数}
引用debugtalk中的函数### debugtalk.py # "随机在某最小值和某最大值的范围内生成多少个整数组成的列表" def get_randomint(min, max, count=None): randomint_list = [] for i in range(count): randomint_list.append(random.randint(min, max)) return randomint_list def setup_case(case_name): print("测试用例 s% 开始执行" % case_name) def teardown_case(case_name): print("测试用例 s% 执行结束" % case_name) def setup_step(case_step): print("测试步骤 s% 开始执行" % case_step) def teardown_step(case_step): print("测试步骤 s% 执行结束" % case_step) if __name__ == "__main__": print(get_randomint(1, 20, 10)) ### testsuit.yml config: name: 参数化测试套件 testcases: - name: 这里引用testcases中的测试用例 testcase: testcases/test01.yml parameters: search_word: ${get_randomint(1, 20, 5)} # 引用debugtalk中的函数 ### test01.yml - config: name: 测试用例,被上面测试套件引用 base_url: https://www.baidu.com - test: name: 百度搜索 request: url: /s method: GET params: wd: $serch_word header: ...
12、跳过执行:只能在testcases中设置
- 无条件跳过:
skip
- 条件为真跳过:
skipIf
- 条件为假跳过:
skipUnless
### test01.yml
- config:
name: 测试用例,被测试套件引用
base_url: https://www.baidu.com
- test:
skip: 无条件跳过 # ----------> a. 无条件跳过:skip
name: 百度搜索
request:
...
validate:
-eq: ["status_code", 200]
- test:
skipIf: 百度搜索2 # ---------> a. 条件为真跳过:skipIf,非空、非0、True时跳过执行
name: 百度搜索2
request:
...
validate:
-eq: ["status_code", 200]
- test:
skipUnless: # ----------> a. 条件为假跳过:skipUnless,空、0、False时跳过执行
name: 百度搜索3
request:
...
validate:
-eq: ["status_code", 200]
13、重复执行:times
参数,用例中可以设置用例运行的次数
### test01.yml
- config:
name: 测试用例,被测试套件引用
base_url: https://www.baidu.com
- test:
skipUnless: 1
times: 5 # -----------> times设置case运行次数
name: 百度搜索
request:
...
validate:
-eq: ["status_code", 200]
14、用例分层:
Httprunner项目分层为 api接口层,testcases用例层,testsuite测试套件层
-
api接口层:不用在里面加特殊细节的断言,断言接口能否请求通即可。新建api文件夹,下面新建一个yml文件进行接口api的编写。举例:
### E:\Code_local\HttpRunnerDemo\api\test.yml name: "获取access_token" base_url: ${ENV(url)} request: url: /cgi-bin/token method: GET params: grant_type: ${ENV(grant_type)} appid: ${ENV(appid)} secret: ${ENV(secret)} validate: - eq: [status_code, 200]
-
testcases用例层:直接调用接口层中的yml文件执行,细节断言可在这里编写,同时也可以调用其他用例或者其他用例的参数执行。
### test01.yml - config: name: case中调用api文件中的yml文件执行 - test: name: step01:执行获取token的接口 api: api/test.yml # ------------------> 只需要写被调用的api目录下的yml绝对路径即可 validate: - contains: [content, access_token]
-
testsuite测试套件层:新建testsuites目录存放测试套件,将测试用例整合起来执行
### testsuit01.yml config: name: 测试套件整合测试用例进行执行 testcases: - name: 调用testcases中的用例执行 testcase: testcases/test01.yml # ----> 被调用case的绝对路径
15、case之间的相互调用:
可以通过调取用例和调取用例之中的参数进行调用
-
用例之间的简单调用:
testcase
关键字,直接给被调用用例的绝对路径### test01.yml - config: name: 测试用例,被测试套件引用 base_url: https://www.baidu.com - test: name: 调用其他用例 testcase: testcases/test02.yml # -------> 被调用用例的绝对路径 - test: ...
-
用例之间传参的调用:参考【10.4:用例之间传参】
来源:你们的好朋友大强