接口测试平台(一)httprunner

我准备写一个基于httprunner的接口自动化测试平台了,所以先介绍一下httprunner

httprunner

httpRunner 是一个开源的 API 测试工具,支持 HTTP(S)/HTTP2/WebSocket/RPC 等网络协议,涵盖接口测试、性能测试、数字体验监测等测试类型。简单易用,功能强大,具有丰富的插件化机制和高度的可扩展能力。

设计理念

  • 约定大于配置:测试用例是标准结构化的,格式统一,方便协作和维护
  • 标准开放:基于开放的标准,支持与 HAR/Postman/Swagger/Curl/JMeter 等工具对接,轻松实现用例生成和转换
  • 一次投入多维复用:一套脚本可同时支持接口自动化测试、性能测试、数字体验监测等多种 API 测试需求
  • 融入最佳工程实践:不仅仅是一款测试工具,在功能中融入最佳工程实践,实现面向网络协议的一站式测试解决方案

核心特性

  • 网络协议:完整支持 HTTP(S)/HTTP2/WebSocket,可扩展支持 TCP/UDP/RPC 等更多协议
  • 多格式可选:测试用例支持 YAML/JSON/go test/pytest 格式,并且支持格式互相转换
  • 双执行引擎:同时支持 golang/python 两个执行引擎,兼具 go 的高性能和 pytest 的丰富生态
  • 录制 & 生成:可使用 HAR/Postman/Swagger/curl 等生成测试用例;基于链式调用的方法提示也可快速编写测试用例
  • 复杂场景:基于 variables/extract/validate/hooks 机制可以方便地创建任意复杂的测试场景
  • 插件化机制:内置丰富的函数库,同时可以基于主流编程语言(go/python/java)编写自定义函数轻松实现更多能力
  • 性能测试:无需额外工作即可实现压力测试;单机可轻松支撑 1w+ VUM,结合分布式负载能力可实现海量发压
  • 网络性能采集:在场景化接口测试的基础上,可额外采集网络链路性能指标(DNS 解析、TCP 连接、SSL 握手、网络传输等)
  • 一键部署:采用二进制命令行工具分发,无需环境依赖,一条命令即可在 macOS/Linux/Windows 快速完成安装部署

安装说明

参考官网:https://httprunner.com/docs/user-guide/installation/

windows安装

pip命令行安装:pip install httprunner
查看安装是否成功:httprunner -V
安装har2case:pip install har2case
安装httprunner:将httprunner下载解压到本地路径,在系统环境变量中维护该路径

增强测试用例

变量

变量声明

在 HttpRunner 测试用例中,有 4 个地方可以对变量进行声明。

声明全局变量(config variables)
在 config 下声明的 variables 为测试用例全局变量,作用域为整个测试用例,在测试用例的所有地方都可以引用。

声明数据驱动(parameters)
在 config 下声明的 parameters 为测试用例的驱动参数;它的作用域也是覆盖整个测试用例,在测试用例的所有地方都可以引用。

声明局部变量(teststeps variables)
在单个测试步骤(teststep)下声明的 variables 是测试步骤局部变量,作用域仅限当前步骤。

各个测试步骤的变量相互独立,互不影响。

提取参数变量(session variables)
还有一种变量声明的方式,可以在某个测试步骤(teststep)中提取(extract)特定的响应参数,并赋值给指定的变量名。该操作也常被成为 参数关联。

提取的参数变量类似于 session 参数,作用域为当前步骤及之后的步骤。

变量引用

在 HttpRunner 的测试用例中,约定通过 ${} 或 $ 的形式来引用变量。

例如:$var 或 ${var}

大多数情况下,采用 $var 或 ${var} 这两种形式都是可以的。但如果在某些字段中存在部分引用变量的情况,例如 abc123def 中 123 需要引用变量,那么就只能使用 ${var} 的形式,即 abc${num}def;如果使用 abc$numdef 的话,变量名称会被识别为 numdef。

另一种需要说明的情况,如果在测试用例中本身就存在 $ 符号,那么可以通过 $$ 进行转义。

例如,测试用例中某个字段的原始内容为 $m,那么为了避免将其解析为变量,则需要将其写为 $$m。

变量优先级

针对上述的 4 类变量类型,如果声明的变量名称出现重复,则会按照一定的优先级策略进行处理。

优先级从高到低依次为:step variables > session variables > parameter variables > config variables

示例

config:{
    "name": xxx
    "variables":  {			# config variables
        "varA": "configA"
        "varB": "configB"
        "varC": "configC"
    }
    "parameters" : {		# parameters variables
		"varA-varB": [
			["paramA1", "paramB1"],
			["paramA2", "paramB2"],
		]
    }
}

teststeps:[
	{
		"name": "step 1"
		"variables":  {		# step variables
			"varA": "step1A"
		},
		"request": {
			"method" : "GET"
			"url" : /$varA/$varB/$varC  # varA="step1A", varB="paramB1", varC="configC"
		}
		"extract": {
			"varA": "body.data.A", # suppose varA="extractVarA"
			"varB": "body.data.B"  # suppose varB="extractVarB"
		}
	},
	{
		"name": "step 2"
		"varialbes": {		# step variables
			"varA" : "step2A"
		}
		"request": {
			"url" : /$varA/$varB/$varC # varA="step2A", varB="extractVarB", varC="configC"
			"method" : "GET"
		}
	}
]

在步骤 1 中:

varA 定义了局部变量,优先级最高,因此实际值为 step1A
varB 未定义局部变量,将继承全局变量;而在全局变量中,parameter 的优先级高于 variables,因此 varB 实际值为 paramB1
varC 未定义局部变量,将继承全局变量;在全局变量中,varC 仅在 variables 中进行了声明,因此 varC 的实际值为 configC
在步骤 2 中:

varA 定义了局部变量,优先级最高,因此实际值为 step2A
varB 未定义局部变量;而步骤 1 中有提取该变量,优先级高于全局变量,因此 varB 实际值为 extractVarB
varC 未定义局部变量,也不存在同名 session 变量,将继承全局变量,因此 varC 实际值为 configC

参数提取

目前,HttpRunner 支持 2 种响应结果字段提取方式。

提取的参数变量类似于 session 参数,作用域为当前步骤及之后的步骤,引用方式与普通的变量一致。

jmespath 表达式

若响应结果为 JSON 结构,支持采用 jmespath 表达式进行参数提取。

jmespath 是一种 JSON 查询语言,可以使用非常灵活且强大的表达式查询 JSON 数据结构中的字段,并返回符合条件的数据。
示例:

{
  "locations": [
    {"name": "Seattle", "state": "WA"},
    {"name": "New York", "state": "NY"},
    {"name": "Bellevue", "state": "WA"},
    {"name": "Olympia", "state": "WA"}
  ]
}
  • 查询所有城市名称:locations[*].name
  • 查询第二个城市名称:locations[1].name => “New York”
  • 查询最后一个州名:locations[-1].state => “WA”
    1、extract 的对象仅有 5 种类型:
    status_code:提取响应状态码,例如 200、404
    proto:提取协议类型,例如 “HTTP/2.0”、“HTTP/1.1”
    headers:从响应 headers 中提取字段,例如 headers.name
    cookies:从响应 cookies 中提取字段,例如 cookies.Token
    body:从响应 body 中提取字段,例如 body.args.foo1
    2、如果表达式中存在 - 的情况,那么需要加引号处理。
    例如 headers."Content-Type"
"teststeps": [
	{
		"name": "",
		"variables": {
			"name": "demo"
		},
		"request": {
			"method": "POST",
			"url": "https://www.httpbin.org",
			"params": {},
			"headers": {
				"name": "$name",
				"Content-Type": "text/plain"
			},
			"body": ""
		},
		"validate": [],
		"extract": {
			"name": "body.headers.Name"
		}
	}
]

正则表达式

若响应结果为 text/html 格式,支持采用正则表达式的方式提取目标参数。

例如响应的 body 为:

<html>
<title>参数提取(extract) | HttpRunner</title>
</html>

如果我们想提取页面的 title 字段,就可以这样做:(.*)

即在提取表达式中指定目标参数的左右边界,然后将目标参数替换为 (.*);这样我们就能将正则匹配到的值赋值给参数变量了。

"teststeps": [
	{
		"name": "",
		"variables": {
			"name": "demo"
		},
		"request": {
			"method": "GET",
			"url": "https://www.httpbin.org",
			"params": {},
			"headers": {
				"name": "$name",
				"Content-Type": "text/plain"
			}
		},
		"validate": [],
		"extract": {
			"title": "<title>(.*)</title>"
		}
	}
]

自定义函数

使用 python 语言编写方式,仅需在项目根目录 debugtalk.py 中编写自定义函数即可,无需进行额外编译。同时,使用 hrp run/boom 也兼容 v4.0 版本之前的写法。

import logging
import time
from typing import List


def get_user_agent():
    return "hrp/funppy"


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}"

注意:使用 hrp 进行测试时,hrp 会根据 debugtalk.py 文件生成程序可直接调用的 .debugtalk_gen.py 文件,请勿编辑。

运行接口测试

测试报告

用 hrp run 执行接口测试时,我们可以通过添加启动参数 --gen-html-report 在当前项目根目录的 reports 中生成一份 HTML 格式的测试报告。测试报告的输出名称为:report-unix时间戳。
报告样式:
报告样式如下所示,与 HttpRunner v2.x 版本保持一致。

报告说明:
在 Summary 中,会罗列本次测试的整体信息,包括测试开始时间、总运行时长、运行的 Go 版本和系统环境、运行结果统计数据。

在 Details 中,会详细展示每一条测试用例的运行结果。

其中,每一条测试用例对应一个 log 按钮,点击 log 按钮,会在弹出框中展示该用例执行的详细数据,包括请求的 headers 和 body、响应的 headers 和 body、校验结果、响应、响应耗时(elapsed)等信息。具体细节如下图所示:

此外,若测试用例运行不成功(error),则在该测试用例的 Detail 中会出现 traceback 按钮,点击该按钮后,会在弹出框中展示失败原因。

综上所述,我之所以选择基于httprunner来开发接口测试平台,是因为他可以通过录制自动生成用例,并且支持不同格式用例相互转换,json格式用例在前后端交互过程中也方便处理数据。

posted @ 2022-07-13 11:11  、阿红吖  阅读(943)  评论(0编辑  收藏  举报