HttpRunner 3.x接口自动化: 全面讲解如何落地实战

今天,我们来一起学习下HttpRunner3。主要讲解如何使用、应用技巧、基本知识点总结和需要注意事项。一篇文章没法面面俱到,如果有重要的地方没写到,可以给我留言,咱们接着补充。

整体概览

概述介绍

HttpRunner 是一款面向 HTTP(S) 协议的通用测试框架,只需编写维护一份 YAML/JSON 脚本,即可实现自动化测试、性能测试、线上监控、持续集成等多种测试需求。

官方文档

文档中的内容更详细,使用过程遇到问题多来看看吧。

GitHub - httprunner/httprunner: HttpRunner 是一个开源的 API/UI 测试工具,简单易用,功能强大,具有丰富的插件化机制和高度的可扩展能力。
HttpRunner V3.x Docs

大佬翻译的版本:

HttpRunner V3.x中文文档

设计理念

相比于其它 API 测试工具,HttpRunner 最大的不同在于设计理念。
约定大于配置:测试用例是标准结构化的,格式统一,方便协作和维护
充分复用优秀的开源项目,不追求重复造轮子,而是将强大的轮子组装成战车
追求投入产出比,一份投入即可实现多种测试需求

关键特性

  • 继承的所有强大功能requests ,只需以人工方式获得乐趣即可处理HTTP(S)。
  • 以YAML或JSON格式定义测试用例,pytest 以简洁优雅的方式运行。
  • HAR 支持下记录并生成测试用例。
  • 支持variables/ extract/ validate/hooks机制,以创建非常复杂的测试方案。
  • 使用debugtalk.py插件,任何功能都可以在测试用例的任何部分使用。
  • 使用jmespath ,提取和验证json响应从未如此简单。
  • 有了pytest ,数百个插件随时可用。
  • 使用allure ,测试报告可以非常强大。
  • 通过重复使用locust ,您可以进行性能测试,而无需进行额外的工作。
  • 支持CLI命令,与CI/CD完美结合。

简单的总结下:

  1. HttpRunner继承了所有requests的强大功能,可以用YAML或JSON格式编写测试用例,以pytest方式运行。

  1. 支持HAR 格式的录制文件生成测试用例,支持variables/ extract/ validate/hooks机制,能够创建非常复杂的测试方案。

  1. 可以借助debugtalk.py强大的插件功能助力编写测试用例,提取和验证json响应使用jmespath 。

核心概念

测试用例(testcase)应该是完整且独立的,每条测试用例应该是都可以独立运行的
测试用例是测试步骤(teststep)的 有序 集合,每一个测试步骤对应一个 API 的请求描述
测试用例集(testsuite)是测试用例的 无序 集合,集合中的测试用例应该都是相互独立,不存在先后依赖关系的;如果确实存在先后依赖关系,那就需要在测试用例中完成依赖的处理

测试步骤(teststep)

测试用例是测试步骤的 有序 集合,而对于接口测试来说,每一个测试步骤应该就对应一个 API 的请求描述。

测试用例(TestCase)

从 2.0 版本开始,HttpRunner 开始对测试用例的定义进行进一步的明确:
一条测试用例(testcase)应该是为了测试某个特定的功能逻辑而精心设计的,并且至少包含如下几点:
明确的输入(inputs)
明确的运行环境(execution conditions)
明确的测试步骤描述(testing procedure)
明确的预期结果(expected results)
对应地,HttpRunner 的测试用例描述方式进行如下设计:
测试用例应该是完整且独立的,每条测试用例应该是都可以独立运行的
在 HttpRunner 中,每个 YAML/JSON/pytest/go test 文件对应一条测试用例
HttpRunner 以 TestCase 为核心,将任意测试场景抽象为有序步骤的集合
包含且仅有两部分:
Config:测试用例的公共配置部分,包括用例名称、base_url、参数化数据源、是否开启 SSL 校验等
TestSteps:有序步骤的集合;采用了 go interface 的设计理念,支持进行任意协议和测试类型的拓展;步骤内容统一在 Run 方法中进行实现。

测试用例集(testsuite)

测试用例集 是 测试用例 的 无序 集合,集合中的测试用例应该都是相互独立,不存在先后依赖关系的。

测试场景

测试场景 和 测试用例集 是同一概念,都是 测试用例 的 无序 集合。
接口
测试用例集
参数
变量
测试脚本(YAML/JSON)
debugtalk.py
环境变量

项目根目录

项目根目录以debugtalk.py为锚, 测试用例中的相对路径(例如引用测试用例或CSV文件)都基于此根路径。

变量优先级

理解起来就是:局部优先于全局,离得越近,越优先。

测试用例变量(testcase variables) > export variables > testsuite config variables > 被引用用例配置变量(referenced testcase config variables)
优先级可能会令人困惑。 避免混淆的最好方法是使用不同的变量名。 但是,如果必须使用相同的变量名,则应该了解优先级策略。
版本对比

注意点:

Httprunner2 的用例目录是三级:api/case/suit,Httprunner3 的用例目录是:case/suit,但是生成的目录没有suit,需要的可以自己加。你可以将API定义为只有一个请求步骤的测试用例。


环境准备

测试环境python3.9,httprunner版本为3.1.11

安装指定版本

如果不指定版本号,默认会安装最新的4+版本。

安装

pip install httprunner==3.1.11
验证

httprunner -Vhrun -V

查看帮助信息


httprunner -h

usage: httprunner [-h] [-V] {run,startproject,har2case,make} ...One-stop solution for HTTP(S) testing.positional arguments:  {run,startproject,har2case,make}                        sub-command help    run                 Make HttpRunner testcases and run with pytest.    startproject        Create a new project with template structure.    har2case            Convert HAR(HTTP Archive) to YAML/JSON testcases for                        HttpRunner.    make                Convert YAML/JSON testcases to pytest cases.optional arguments:  -h, --help            show this help message and exit  -V, --version         show version

脚手架建项目


httprunner  startproject  HttpRunnerThreeDemo
目录说明
debugtalk.py(可选):存储项目中逻辑运算辅助函数
该文件存在时,将作为项目根目录定位标记,其所在目录即被视为项目工程根目录
该文件不存在时,运行测试的所在路径(CWD)将被视为项目工程根目录
测试用例文件中的相对路径(例如.csv)均需基于项目工程根目录
运行测试后,测试报告文件夹(reports)会生成在项目工程根目录
YAML/JSON/Python(必须):测试用例文件,存储接口测试相关信息
.env(可选):存储项目环境变量,通常用于存储项目敏感信息
reports:默认生成测试报告的存储文件夹
testcases: 测试用例存放目录
har 可以存放录制导出的文件

演练网站

本次依旧使用pity作为我们的测试网站,建议优先本地部署,方便调试以及后续的各种练习。用例中的接口我们采用F12的方式获得。

pity是一款专注于api自动化的工具,采用Python+FastApi+React开发。

项目实战

HttpRunner-小试牛刀

编写用例
# demo_testcase_login_test.py
config:    
  name: "request methods testcase: reference testcase"
teststeps:    
   - name: pity登录        
      request:            
           url: http://127.0.0.1:7777/auth/login            
           method: POST            
           headers:  Content-Type: "application/json"            
           json:                  
           "username": "tester"                  
           "password": "tester"        
      extract:            
           - code: "json.code"        
      validate:           
          - eq: ["$code", 0]
运行用例

hrun  demo_testcase_login.yml

通过上面,我们看到httprunner执行用例的时候会先生成py文件的测试用例,再以 pytest的方式运行测试用例。

生成用例
执行完yml文件会自动生成py文件的用例。

# NOTE: Generated By HttpRunner v3.1.11# FROM: testcases/demo_testcase_login.ymlfrom httprunner import HttpRunner, Config, Step, RunRequest, RunTestCaseclass TestCaseDemoTestcaseLogin(HttpRunner):    
config = Config("request methods testcase: reference testcase")    
teststeps = [        Step(            RunRequest("pity登录")            .post("http://127.0.0.1:7777/auth/login")            .with_headers(**{"Content-Type": "application/json"})            .with_json({"username": "tester", "password": "tester"})            .extract()            .with_jmespath("body.code", "code")            .validate()            .assert_equal("$code", 0)        ),    ]
  if __name__ == "__main__":    TestCaseDemoTestcaseLogin().test_start()

同样的,我们可以直接执行刚刚生成的.py用例:


python demo_testcase_login_test.py 

HttpRunner-用例转换

以后会搞个小小的专题,专门分析一下市面上的用例录制,转换,回放等工具的用法及对比,敬请期待。

HttpRunner-数据驱动

用例优先级遵循如下规则:
step variables > extracted variables, e.g. step 2, varA="step2A"
parameter variables > config variables, e.g. step 1, varB="paramB1"
extracted variables > parameter variables > config variables, e.g. step 2, varB="extractVarB"
config variables are in the lowest priority, e.g. step 1/2, varC="configC"

【注】step-步骤,parameter-参数,valuables-全局定义的。

config:    
   name: xxx    
   variables:              # config variables       
      varA: "configA"        
      varB: "configB"        
      varC: "configC"    
   parameters:             # parameter variables        
      varA: ["paramA1"]        
      varB: ["paramB1"]
teststeps:
    -    name: step 1    
         variables:              # step variables        
              varA: "step1A"    
         request:        
              url: /$varA/$varB/$varC # varA="step1A", varB="paramB1", varC="configC"        
              method: GET    
          extract:                # extracted variables        
              varA: body.data.A   # suppose varA="extractVarA"        
               varB: body.data.B   # suppose varB="extractVarB"
     -    name: step 2    
           varialbes:        
               varA: "step2A"    
           request:        
               url: /$varA/$varB/$varC # varA="step2A", varB="extractVarB", varC="configC"        
           method: GET

下面对上面的参数化方式进行举例,验证(为了讲解方便,未使用环境变量的参数化方式)。

HttpRunner-参数化1

在config:variables中编写测试数据,测试步骤中引用。
编写用例
config:    name: "request methods testcase: params testcase"    base_url: http://127.0.0.1:7777    variables:              username: "tester"              password: "tester"teststeps:    -        name: pity登录        request:            url: /auth/login            method: POST            headers:                Content-Type: "application/json"            json:                  "username": $username                  "password": $password        extract:            - code: "json.code"        validate:           - eq: ["$code", 0]
运行用例

hrun  hr_params/demo_testcase_login_params.yml
生成用例
执行完yml文件会自动生成py文件的用例。

# NOTE: Generated By HttpRunner v3.1.11# FROM: testcases/hr_params/demo_testcase_login_params.yml
from httprunner import HttpRunner, Config, Step, RunRequest, RunTestCaseclass TestCaseDemoTestcaseLoginParams(HttpRunner):    
config = (        Config("request methods testcase: params testcase")        .variables(**{"username": "tester", "password": "tester"})        .base_url("http://127.0.0.1:7777")    )    teststeps = [        Step(            RunRequest("pity登录")            .post("/auth/login")            .with_headers(**{"Content-Type": "application/json"})            .with_json({"username": "$username", "password": "$password"})            .extract()            .with_jmespath("body.code", "code")            .validate()            .assert_equal("$code", 0)        ),    ]if __name__ == "__main__":    TestCaseDemoTestcaseLoginParams().test_start()

HttpRunner-参数化2

conifg: parameters,teststeps:variables 中使用变量的情况。
编写用例

config:    name: "request methods testcase: params testcase"    base_url: ${ENV(BASE_URL)}#    variables:#              username: "tester"#              password: "tester"    parameters:        username-password:            - [ "tester","tester" ]teststeps:    -        name: pity登录        request:            url: /auth/login            method: POST            headers:                Content-Type: "application/json"            json:                  "username": $username                  "password": $password        extract:            - code: "json.code"        validate:           - eq: ["$code", 0]

#.envUSERNAME=leoleePASSWORD=123456BASE_URL=http://127.0.0.1:7777
运行用例

加上-s打印的信息更全面。


 hrun demo_testcase_login_params_parameters.yml  -s
生成用例
执行完yml文件会自动生成py文件的用例。

# NOTE: Generated By HttpRunner v3.1.11# FROM: testcases/hr_params/demo_testcase_login_params_parameters.ymlimport pytestfrom httprunner import Parametersfrom httprunner import HttpRunner, Config, Step, RunRequest, RunTestCaseclass TestCaseDemoTestcaseLoginParamsParameters(HttpRunner):    @pytest.mark.parametrize(        "param", Parameters({"username-password": [["tester", "tester"]]})    )    def test_start(self, param):        super().test_start(param)    config = Config("request methods testcase: params testcase").base_url(        "${ENV(BASE_URL)}"    )    teststeps = [        Step(            RunRequest("pity登录")            .post("/auth/login")            .with_headers(**{"Content-Type": "application/json"})            .with_json({"username": "$username", "password": "$password"})            .extract()            .with_jmespath("body.code", "code")            .validate()            .assert_equal("$code", 0)        ),    ]if __name__ == "__main__":    TestCaseDemoTestcaseLoginParamsParameters().test_start()

HttpRunner-参数化3

登录---增加项目---查询项目,一个复杂点的例子。
step variables ,extract variables,parameter variables ,config variables变量优先级使用情况。大家可以将本例中的参数随意更改,亲手验证。
经过思考,我认为我们可以选择一种适合自己的方式进行参数化。实际过程中也就调试的时候会将值写死在步骤中。为了方便,建议是最好写在config中,其中写到parameters最合适不过了,这样省去了后续数据驱动的麻烦。
编写用例

config:    name: "request methods testcase: params testcase"    base_url: http://192.168.0.123:7777  # 本机的pity不工作了,赶紧换了个电脑,大佬们看到了可以改成自己的IP哦--彩蛋。#    variables:#         username: "tester_config_var1"#         password: "tester_config_var1"    parameters:            username-password-name-app:              - ["tester","tester","aa","aa"]teststeps:    -        name: pity登录        request:            url: /auth/login            method: POST            headers:                Content-Type: "application/json"            json:                  "username": $username                  "password": $password        extract:            - code: "json.code"            - token: body.data.token        validate:           - eq: ["$code", 0]    -        name: 创建项目        request:          url: /project/insert          method: POST          headers:            Content-Type: "application/json"            token: "$token"          json:              {"name": "${name}","app":"${app}","owner":2,"private":false}        extract:          - code: "json.code"   ## 提取到的变量,我们后面涉及到关联的再介绍它        validate:          - eq: [ "$code", 0 ]    -        name: 查询项目信息        request:            url: /project/list            method: GET            headers:                Content-Type: "application/json"                token: "$token"            params:                page: 1                size: 8        extract:            - code: "json.code"            - name: "json.data[0].name"        validate:            - eq: ["$code", 0]            - eq: ["$name", "${name}"]
运行用例

 hrun  create_project_params_parameters.yml
生成用例
执行完yml文件会自动生成py文件的用例。

# NOTE: Generated By HttpRunner v3.1.11# FROM: testcases/hr_params2/create_project_params_parameters.ymlimport pytestfrom httprunner import Parametersfrom httprunner import HttpRunner, Config, Step, RunRequest, RunTestCaseclass TestCaseCreateProjectParamsParameters(HttpRunner):    @pytest.mark.parametrize(        "param",        Parameters({"username-password-name-app": [["tester", "tester", "aa", "aa"]]}),    )    def test_start(self, param):        super().test_start(param)    config = Config("request methods testcase: params testcase").base_url(        "http://192.168.0.123:7777"    )    teststeps = [        Step(            RunRequest("pity登录")            .post("/auth/login")            .with_headers(**{"Content-Type": "application/json"})            .with_json({"username": "$username", "password": "$password"})            .extract()            .with_jmespath("body.code", "code")            .with_jmespath("body.data.token", "token")            .validate()            .assert_equal("$code", 0)        ),        Step(            RunRequest("创建项目")            .post("/project/insert")            .with_headers(**{"Content-Type": "application/json", "token": "$token"})            .with_json(                {"name": "${name}", "app": "${app}", "owner": 2, "private": False}            )            .extract()            .with_jmespath("body.code", "code")            .validate()            .assert_equal("$code", 0)        ),        Step(            RunRequest("查询项目信息")            .get("/project/list")            .with_params(**{"page": 1, "size": 8})            .with_headers(**{"Content-Type": "application/json", "token": "$token"})            .extract()            .with_jmespath("body.code", "code")            .with_jmespath("body.data[0].name", "name")            .validate()            .assert_equal("$code", 0)            .assert_equal("$name", "${name}")        ),    ]if __name__ == "__main__":    TestCaseCreateProjectParamsParameters().test_start()
创建成功

HttpRunner-参数化4


hrun  create_project_params_debugtalk.yml

在debugtalk.py中参数化,详见后面的代码地址,这里不再展示。

注意:

step中不支持从debugtalk中读取函数返回值。

小小的总结一下下

配置变量(config variables):用于数据解藕:字典类型,定义在config或者teststep中。

参数变量(parameter variables):用户参数化,列表类型,定义在config。

HttpRunner-testsuit使用

编写用例

config:    name: "demo testsuite"testcases:    -        name: "suitdemo"        testcase: hr_params2/create_project_params_debugtalk.yml  #以源码为准,路径太长,我这里写不下了。
运行用例

hrun create_project_testsuit.yml
生成报告

hrun  create_project_testsuit.yml  --html=report/report.html

关于用例套件也涉及到变量的问题,此处只给出结论,以后再讲吧,写不动了。

测试用例变量(testcase variables) > export variables > testsuite config variables > 被引用用例配置变量(referenced testcase config variables)

config:    name: xxx    variables:                  # testsuite config variables        varA: "configA"        varB: "configB"        varC: "configC"testcases:-    name: case 1    variables:                  # testcase variables        varA: "case1A"    testcase: /path/to/testcase1    export: ["varA", "varB"]    # export variables-    name: case 2    varialbes:                  # testcase variables        varA: "case2A"    testcase: /path/to/testcase2

HttpRunner-hooks机制

牛刀小试
编写用例

config:    name: "request methods testcase: params testcase"    base_url: http://192.168.0.123:7777  # 本机的pity不工作了,赶紧换了个电脑,大佬们看到了可以改成自己的IP哦--彩蛋    variables:         username: "tester"         password: "tester"teststeps:    -        name: pity登录        request:            url: /auth/login            method: POST            headers:                Content-Type: "application/json"            json:                  "username": $username                  "password": $password        extract:            - code: "json.code"            - token: body.data.token        validate:           - eq: ["$code", 0]    -        name: 创建项目        setup_hooks:            - ${hook_before_add($request)}        teardown_hooks:            - ${hook_after_teardown($response)}        request:          url: /project/insert          method: POST          headers:            Content-Type: "application/json"            token: "$token"          data:              {"name": "aaa","app":"aaa","owner":2,"private":false}        extract:          - code: "json.code"   ## 提取到的变量,我们后面涉及到关联的再介绍它        validate:          - eq: [ "$code", 0 ]

# debugtalk.pydef hook_before_add(request):    print("====")    print(request)    data={}    data['name']="bbb"    data['app']="bbb"    data['owner']=2    data['private']=False    request['data']=json.dumps(data)def hook_after_teardown(response):    print("==========")    print(response.json)
运行用例

hrun create_project_hooks.yml  -s
创建成功

成功的将用例中的项目由aaa修改为bbb,说明我们的hook调用成功了。

文章源码

https://gitee.com/rdtest/code2022/tree/master/HttpRunnerThreeDemo

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值