HttpRunner is a simple & elegant, yet powerful HTTP(S) testing framework.

本文主要记录特定版本: v==3.0.1 的相关使用心得。


版本选择

当前最新版本是 3.1.4 ,该版本作者推荐使用 .py 文件进行脚本编写和维护,主要是为了复用 IDE 的链式调用功能, 不过个人并不喜欢,同时新版本在兼容旧版本脚本方面存在一定问题,迁移工作量较大。

因此个人还是推荐使用 3.0.1 版本,这个版本和 2.0.x 版本使用很接近,因此我们在使用中可以看一下 2.0.x文档

3.0.x 的官方文档在 这里

同时,这里提供一份他人翻译的 中文文档, 个人觉得还是写的挺好,不仅仅是翻译。


安装

1
$pip install httprunner==3.0.1 -i https://mirrors.aliyun.com/pypi/simple/

鉴于国内的网络环境,因此我们使用一个 -i 参数来指定 pypi 源。


创建一个 demo

使用如下命令:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
$httprunner --startproject demo 
# 官方文档startproject前是不需要加--的
# 但是-h参数表示需要加,不加也的确会报错
httprunner.utils:create_scaffold:359 - Start to create new project: demo
httprunner.utils:create_folder:365 - created folder: demo
httprunner.utils:create_folder:365 - created folder: demo\api
httprunner.utils:create_folder:365 - created folder: demo\testcases
httprunner.utils:create_folder:365 - created folder: demo\testsuites
httprunner.utils:create_folder:365 - created folder: demo\reports
httprunner.utils:create_file:371 - created file: demo\api\demo_api.yml
httprunner.utils:create_file:371 - created file: demo\testcases\demo_testcase.yml
httprunner.utils:create_file:371 - created file: demo\testsuites\demo_testsuite.yml
httprunner.utils:create_file:371 - created file: demo\debugtalk.py
httprunner.utils:create_file:371 - created file: demo\.env
httprunner.utils:create_file:371 - created file: demo\.gitignore

生成的文件目录结构:

从上面的目录结构能够很清楚看出来,这个版本的 HttpRunner 分了 3 层:api 层、testcase 层、testsuite 层。

ps.最新版本推荐分两层,个人觉得也可以接受

因为设定了 testcase 里可以调 testcase

感兴趣可以建一个最新版的 demo 看下


mock 一个接口用于测试

接口文档:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
host: http://127.0.0.1:8000
method: post
url: /insert
请求参数:
{
  "name": "string",
  "age": 0,
  "address": "string",
  "salary": 0
}

响应:
{
  "success": true,
  "msg": "此人名字叫做:{name},十年后此人年龄:{age+10}"
}

编写脚本

根据上面的接口文档,我们可以写出如下脚本

api 层:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
$cat api/demo_api.yml
name: demo api
variables:
    body:
        name: $name
        age: $age
        address: $address
        salary: $salary
request:
    url: /insert
    method: POST
    headers:
        Content-Type: "application/json"
    json: $body
validate:
    - eq: ["status_code", 200]

testcase 层:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
config:
    name: "demo testcase"
    base_url: "http://127.0.0.1:8000"

teststeps:
-
    name: demo testcase
    api: api/demo_api.yml
    variables:
        name: noel
        age: 15
        address: beijing
        salary: 7777
    extract:
        - msg: content.msg
    validate:
        - eq: ["status_code", 200]

testsuite 层:

1
2
3
4
5
6
7
8
config:
    name: "demo testsuite"
    base_url: "http://127.0.0.1:5000"

testcases:
-
    name: call demo with api data
    testcase: testcases/demo_testcase.yml

执行一下脚本

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
$hrun testsuites/demo_testsuite.yml
2021-04-28 23:16:37.317 | INFO     | httprunner.api:run:334 - HttpRunner version: 3.0.1
2021-04-28 23:16:37.318 | INFO     | httprunner.loader.load:load_dot_env_file:172 - Loading environment variables from /Users/jiawang/PycharmProjects/oldhttprunner/demo/.env
2021-04-28 23:16:37.343 | INFO     | httprunner.api:_run_suite:146 - Start to run testcase: call demo with api data
2021-04-28 23:16:37.343 | INFO     | httprunner.report.html.result:startTest:30 - demo testcase
2021-04-28 23:16:37.344 | INFO     | httprunner.runner:_run_test:242 - POST http://127.0.0.1:8000/insert
2021-04-28 23:16:37.350 | INFO     | httprunner.client:request:221 - status_code: 200, response_time(ms): 6.15 ms, response_length: 79 bytes

.

----------------------------------------------------------------------
Ran 1 test in 0.007s

OK
2021-04-28 23:16:37.363 | INFO     | httprunner.report.html.gen_report:gen_html_report:34 - Start to render Html report ...
2021-04-28 23:16:37.396 | INFO     | httprunner.report.html.gen_report:gen_html_report:61 - Generated Html report: /Users/jiawang/PycharmProjects/oldhttprunner/demo/reports/20210428T151637.343656.html

贴一下测试报告里的请求与响应

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
Request:
url	http://127.0.0.1:8000/insert
method	POST
headers	
{
  "User-Agent": "python-requests/2.25.1",
  "Accept-Encoding": "gzip, deflate",
  "Accept": "*/*",
  "Connection": "keep-alive",
  "Content-Type": "application/json",
  "HRUN-Request-ID": "4d2a31e2-481d-425d-8718-540aa8b342bb",
  "Content-Length": "65"
}
body	
{
  "name": "noel",
  "age": 15,
  "address": "beijing",
  "salary": 7777
}

Response:
ok	True
url	http://127.0.0.1:8000/insert
status_code	200
reason	OK
cookies	{}
encoding	utf-8
headers	
{
  "date": "Wed, 28 Apr 2021 15:16:36 GMT",
  "server": "uvicorn",
  "content-length": "79",
  "content-type": "application/json"
}
content_type	application/json
body	
{
  "success": true,
  "msg": "此人名字叫做:noel,十年后此人年龄:25"
}

变量权重(重点)

在每一层都可以定义变量,但是各层的权重是不同的。api 层拥有最高的权重, 其次是 testcase,最后是testsuite。 即如果你已经在 api 层把一个常量赋值给了一个变量, 那么即使你在 testcase 或者 testsuite 层再去给这个变量赋值, 也不会生效。

我们可以看一下上面的脚本,我在 testcasetestsuite 中都有对 base_url 进行赋值, 但是最后测试报告中的 base_urltestcase 里的。

官方关于变量权重的说明,在 这里


数据驱动

HttpRunner 中建议使用的数据文件是 CSV

以上面 mock 的接口为例

我们在 data.csv 文件中写入如下数据:

1
2
3
name,age,address,salary
noel,15,1,5000
张三,25,北京,8000

那么我们的脚本就需要做如下变动:

1.api 层不需要做改动

2.testcase 层做如下改动:

    去除在这一层对变量(csv文件中包含了的变量)的赋值

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
config:
    name: "demo testcase"
    base_url: "http://127.0.0.1:8000"

teststeps:
-
    name: demo testcase
    api: api/demo_api.yml
    extract:
        - msg: content.msg
    validate:
        - eq: ["status_code", 200]

3.testsuite 层做如下改动:

    新增 parameters 参数,使用 - 拼接 csv 文件中的第一行数据

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
config:
    name: "demo testsuite"
    base_url: "http://127.0.0.1:5000"

testcases:
-
    name: call demo with api data
    testcase: testcases/demo_testcase.yml
    parameters:
        name-age-address-salary: ${P(data/data.csv)}

大工告成,再次执行上面的命令,此时就会跑两次这个接口


自定义函数

因为 httprunner 规范了太多,以及使用 yaml 文件来维护用例, 使得我们的自由度降低很多,为了弥补这一缺点, 作者留下了 debugtalk.py 文件,方便我们自定义参数

我们以一个随机生成名字的函数举例说明如何自定义函数以及调用

首先编辑 debugtalk.py 文件

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
import random

def get_name():
    """
    随机生成一个 name 
    """
    data = []
    for i in range(6):
        data.append(random.choice('1234567890qwertyuiopasdfghjklzxcvbnm'))
    return ''.join(data)

调用时建议写在 testcase 层,或者 csv 文件中,二选一

写在 testcase 层:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
config:
    name: "demo testcase"
    base_url: "http://127.0.0.1:8000"

teststeps:
-
    name: demo testcase
    api: api/demo_api.yml
    variables:
        name: ${get_name()}
    extract:
        - msg: content.msg
    validate:
        - eq: ["status_code", 200]

写在 csv 文件中

1
2
3
name,age,address,salary
${get_name()},15,1,5000
${get_name()},25,北京,8000

全文完~