如何使用 Loadgen 来简化 HTTP API 请求的集成测试
引言
在编写 HTTP 服务的过程中,集成测试 1 是保证程序正确性的重要一环,如下图所示,其基本的流程就是不断向服务发起请求然后校验响应的状态和数据等:
为大量的 API 和用例编写测试是一件繁琐的工作,而 Loadgen 2 正是为了简化这一过程而设计的。
一个简单的测试
假定我们在 127.0.0.1:9100
端口监听了一个 Pizza 3 服务,现在我们通过如下配置来测试集合(collection)的创建:
# loadgen.yml
requests:- request:method: PUTurl: http://127.0.0.1:9100/test_create_document
然后运行 loadgen -config loadgen.yml
:
$ loadgen -config loadgen.yml__ ___ _ ___ ___ __ __/ / /___\/_\ / \/ _ \ /__\/\ \ \/ / // ///_\\ / /\ / /_\//_\ / \/ /
/ /__/ \_// _ \/ /_// /_\\//__/ /\ /
\____|___/\_/ \_/___,'\____/\__/\_\ \/[LOADGEN] A http load generator and testing suite.
[INF] warmup started
[INF] loadgen is up and running now.
[INF] [PUT] http://127.0.0.1:9100/test_create_document -
[INF] status: 200, error: <nil>, response: {"success":true,"collection":"test_create_document"}
[INF] warmup finished
...
为了便于阅读,笔者对程序输出进行了简化,实际会略有区别
可以看到,Loadgen 实际上帮我们做了类似这样的操作:
curl -XPUT http://127.0.0.1:9100/test_create_document
一些简单的测试
上述示例中我们只测试了创建单个集合,但是实际情况下短时间内会有许多请求涌入,对于创建大量的集合我们又该如何测试呢?
这里就需要用到变量 4 的概念:
# loadgen.yml
variables:- name: idtype: sequence
requests:- request:method: PUTurl: http://127.0.0.1:9100/test_create_document_$[[id]]
上述配置中,我们定义了一个名为 id
的变量,sequence
是一个特殊的类型——每次被读取时它的值会递增,因此 Loadgen 会不断发起类似这样的请求:
curl -XPUT http://127.0.0.1:9100/test_create_document_0
curl -XPUT http://127.0.0.1:9100/test_create_document_1
curl -XPUT http://127.0.0.1:9100/test_create_document_2
...
在 Pizza 的日志中也记录了这些请求:
$ pizza___ _____ __________ _/ _ \\_ \/ _ / _ / /_\/ /_)/ / /\/\// /\// / //_\\
/ ___/\/ /_ / //\/ //\/ _ \
\/ \____/ /____/____/\_/ \_/[PIZZA] The Next-Gen Real-Time Hybrid Search & AI-Native Innovation Engine.
[INFO] Collection test_create_document_0 created
[INFO] Collection test_create_document_1 created
[INFO] Collection test_create_document_2 created
...
不那么简单的测试
目前为止,我们只是不断的向一个服务“塞”大量的请求,但比起发起请求,我们常常更关心程序的响应是否符合预期,也就是说,响应需要满足我们定义的一些条件,这可以通过 Loadgen 提供的 断言 5 功能来实现:
# loadgen.yml
variables:- name: idtype: sequence
runner:# 检查返回值是否正常assert_error: true# 检查断言是否通过assert_invalid: true
requests:- request:method: PUTurl: http://127.0.0.1:9100/test_create_document_$[[id]]assert:equals:# 注意,这里我们故意设置了一个“不正常”的值,以迫使断言失败_ctx.response.body_json.success: false
在上述配置中,我们启用了 Loadgen 的检查,然后定义了一个会失败的断言:
equals
会校验给定路径_ctx.response.body_json.success
是否与期望值false
相等_ctx.response.body_json
表示 JSON 格式的响应体success
表示响应体中该字段对应的值,可以用path.to.nested.key
来访问嵌套的字段
也就是说,给定响应体 {"success":true,"collection":"test_create_document"}
,Loadgen 会检查 success
的值是否为 false
:
$ loadgen -debug -r 1 -d 3 -config loadgen.yml
#0 request, PUT http://127.0.0.1:9100/test_create_document_$[[id]], assertion failed, skiping subsequent requests
[WRN] '_ctx.response.body_json.success' is not equal to expected value: true
#0 request, PUT http://127.0.0.1:9100/test_create_document_$[[id]], assertion failed, skiping subsequent requests
[WRN] '_ctx.response.body_json.success' is not equal to expected value: true
#0 request, PUT http://127.0.0.1:9100/test_create_document_$[[id]], assertion failed, skiping subsequent requests
[WRN] '_ctx.response.body_json.success' is not equal to expected value: true
#0 request, PUT http://127.0.0.1:9100/test_create_document_$[[id]], assertion failed, skiping subsequent requests
[WRN] '_ctx.response.body_json.success' is not equal to expected value: true
上述命令我们使用了:
-debug
启用更详细的报错-r 1 -d 3
减少发起的请求数(1req/s
持续3s
)还有一个需要注意的细节是
... is not equal to expected value: true
,这里报告的是success
字段实际的值,而不是断言中定义的期望值。
可以看到,Loadgen 每次请求的断言都失败了,不过我们可以通过日志来快速定位出错的原因以便于调试。
更进一步的测试
现在我们创建了大量的空集合,是时候向其中添加一些文档(document)了,但是,一个首要解决的问题是,每次测试创建的集合名称是带有 $[[id]]
这个变量的,我们如何知道应该向哪个集合上传数据呢?一个可靠的解决方案是借助 Loadgen 的寄存器 6 功能:
# loadgen.yml
variables:- name: idtype: sequence
runner:assert_error: trueassert_invalid: true
requests:- request:method: PUTurl: http://127.0.0.1:9100/test_create_document_$[[id]]assert:equals:_ctx.response.body_json.success: trueregister:# 把响应体的 collection 字段赋值给 $[[collection]]- collection: _ctx.response.body_json.collection- request:method: POST# 在上个请求创建的集合里添加一个文档url: http://127.0.0.1:9100/$[[collection]]/_docbody: '{"hello": "world"}'assert:equals:_ctx.response.body_json.result: created
上述示例中,我们利用动态注册的变量记录了每次测试创建的集合以便于后续请求使用。
最后的优化
为了使我们的配置更加灵活和“便携”,我们可以用环境变量来替换一些硬编码的值:
# loadgen.yml
variables:- name: idtype: sequence
runner:assert_error: trueassert_invalid: true
requests:- request:method: PUT# 读取 PIZZA_SERVER 这个环境变量url: $[[env.PIZZA_SERVER]]/test_create_document_$[[id]]assert:equals:_ctx.response.body_json.success: trueregister:- collection: _ctx.response.body_json.collection- request:method: POSTurl: $[[env.PIZZA_SERVER]]/$[[collection]]/_docbody: '{"hello": "world"}'assert:equals:_ctx.response.body_json.result: created
这样就可以通过:
PIZZA_SERVER=http://127.0.0.1:9101 loadgen -config loadgen.yml
在不同的 Pizza 服务上运行测试。
https://en.wikipedia.org/wiki/Integration_testing ↩︎
https://www.infinilabs.com/docs/latest/gateway/getting-started/benchmark ↩︎
https://www.infinilabs.com/en/docs/latest/pizza ↩︎
https://www.infinilabs.com/docs/latest/gateway/getting-started/benchmark#变量的使用 ↩︎
https://www.infinilabs.com/docs/latest/gateway/getting-started/benchmark#返回值判断 ↩︎
https://www.infinilabs.com/docs/latest/gateway/getting-started/benchmark#动态变量注册 ↩︎
相关文章:

如何使用 Loadgen 来简化 HTTP API 请求的集成测试
引言 在编写 HTTP 服务的过程中,集成测试 1 是保证程序正确性的重要一环,如下图所示,其基本的流程就是不断向服务发起请求然后校验响应的状态和数据等: 为大量的 API 和用例编写测试是一件繁琐的工作,而 Loadgen 2 正…...

软件测试面试大家是不是一问到项目就不会了?
软件测试面试中,介绍做过的项目,可以说是必不可少的一道面试题了,对于面试的同学来说,该自己发挥呢? 把项目的所有功能噼里啪啦说一遍就完事了?当然不是,我们要搞清楚,面试官问这个…...

伐木猪小游戏
欢迎来到程序小院 伐木猪 玩法:控制小猪点击屏幕左右砍树,不能碰到树枝,考验手速与眼力,记录分数,快去挑战伐木吧^^。开始游戏https://www.ormcc.com/play/gameStart/199 html <script type"text/javascript…...

0007Java安卓程序设计-ssm基于Android的校园新闻管理系统
文章目录 **摘** **要**目 录开发环境 编程技术交流、源码分享、模板分享、网课教程 🐧裙:776871563 摘 要 网络的广泛应用给生活带来了十分的便利。所以把校园新闻管理与现在网络相结合,利用java技术建设校园新闻管理系统app,实…...

git增加右键菜单
有次不小心清理系统垃圾,把git右击菜单搞没了,下面是恢复方法 将下面代码存为.reg文件,双击后导出生效,注意,你安装的git必须是默认C盘的,如果换了地方要改下面注册表文件中相关的位置 Windows Registry …...

openGauss学习笔记-117 openGauss 数据库管理-设置数据库审计-查看审计结果
文章目录 openGauss学习笔记-117 openGauss 数据库管理-设置数据库审计-查看审计结果117.1 前提条件117.2 背景信息117.3 操作步骤 openGauss学习笔记-117 openGauss 数据库管理-设置数据库审计-查看审计结果 117.1 前提条件 审计功能总开关已开启。需要审计的审计项开关已开…...
学习代码20231106
解释代码:os.environ[“OMP_NUM_THREADS“] “1“ 这行代码涉及到 Python 的 os 模块和环境变量。它的作用是设置名为 “OMPNUMTHREADS” 的环境变量的值为 “1”。让我解释一下各部分的含义: 1.os.environ: 这是 Python 中的一个字典,包含…...

turtle绘制分形树-第10届蓝桥杯省赛Python真题精选
[导读]:超平老师的Scratch蓝桥杯真题解读系列在推出之后,受到了广大老师和家长的好评,非常感谢各位的认可和厚爱。作为回馈,超平老师计划推出《Python蓝桥杯真题解析100讲》,这是解读系列的第5讲。 turtle绘制分形树&…...
【大厂招聘试题】__硬件工程师_2021年“美团”校招
目录 匹配职位:硬件工程师 1.(多选题)单处理系统中,进程P1,P2,P3处于就绪队列,进程P4,P6处于等待队列,P5正占用处理器运行,以下对接下来的运行合理的分析是( ÿ…...
算法通关村第七关|黄金挑战|迭代实现二叉树的前、中、后序遍历
1.迭代实现前序遍历 public List<Integer> preOrderTraversal(TreeNode root) {List<Integer> res new ArrayList<Integer>();if (root null) {return res;}Deque<TreeNode> stack new LinkedList<TreeNode>();TreeNode node root;while (!…...

了解高防服务器的工作原理
在当今互联网时代,网络安全问题日益突出,各种网络攻击层出不穷。为了保护企业的网络安全,高防服务器应运而生。那么,你是否了解高防服务器的工作原理呢?下面就让我们一起来探索一下。 高防服务器是一种能够有效抵御各种网络攻击的…...

AVL树性质和实现
AVL树 AVL是两名俄罗斯数学家的名字,以此纪念 与二叉搜索树的区别 AVL树在二叉搜索树的基础上增加了新的限制:需要时刻保证每个树中每个结点的左右子树高度之差的绝对值不超过1 因此,当向树中插入新结点后,即可降低树的高度&…...

出口贸易媒体发稿推广6个技巧提升品牌知名度-华媒舍
1. 出口贸易媒体介绍 出口贸易媒体是指专注于报道国际贸易、跨境业务和进出口市场的媒体平台。这些媒体对于企业发展来说至关重要,可以帮助品牌扩大影响力、提升知名度,促进商业合作。下面介绍6个出口贸易媒体发稿推广技巧,帮助企业更好地利…...

学习笔记:CANOE模拟LIN主节点和实际从节点进行通信测试
先写点感想,在LIN开发阶段,我一般用图莫斯USB工具来进行模拟主机节点发送数据。后来公司买了CANOE工具就边学习边搭建了LIN的测试工程,网上的资料真的很少,主要是靠自己一点点摸索前进,总算入门。几个月后的今天&#…...

模型可解释性
模型可解释性 前言导读Background1、为什么需要可解释性?2、诞生背景3、研究现状4、常见的模型可解释性方法4.1 基于模型自身的可解释性1)Explanation Generation2)Prototype Network 4.2 基于结果的可解释性 5、应用前景6、面临挑战 前言导读…...

Django初窥门径-自定义用户模型
前言 自定义用户模型在Django应用中是一个重要的话题,它涉及到如何根据您的项目需求以及特定的用户身份验证和授权需求来调整用户模型。在以下前言中,我将讲述为什么自定义用户模型是如此重要以及其潜在的优势: 随着Web应用的不断发展&…...

微信小程序文件上传wx.uploadFile
网页版查看了一下负载要求是这样 wx.uploadFile({url: ${wx.getStorageSync(apiUrl)}//sysFileInfo/upload?token${wx.getStorageSync(token)}, // 仅为示例,非真实的接口地址filePath: files[0].url,name: file,formData: {secretFlag: Y },success: (res) > {…...

支持内录系统声音的Mac录屏软件Omi Recorder
Screen Recorder by Omi是一款功能强大的屏幕录制应用程序。它可用于在Windows和Mac计算机上捕获屏幕,以便进行演示、教程、游戏录制、视频编辑等各种用途。 以下是该应用程序的一些主要特点: 支持高清录制:Omi Screen Recorder可以以高达6…...

一、Hadoop初始化配置(final+ubuntu保姆级教程)
1、配置虚拟机 三台虚拟机,分别为node1、node2、node3,内存分别为4G、2G、2G,现存最好为(>40G),如下: 2、修改主机名 分别打开三台虚拟机,root用户输入一下命令: no…...
Linux常用的包管理工具
Linux系统中有两个常用的包管理工具,分别是yum和apt。 1. yum命令 yum是Red Hat公司开发的一种包管理器,主要用于安装、更新、卸载和管理RPM包。它是基于RPM包管理系统的,可以自动解决软件包依赖关系问题。 常用yum命令: - 安…...

利用最小二乘法找圆心和半径
#include <iostream> #include <vector> #include <cmath> #include <Eigen/Dense> // 需安装Eigen库用于矩阵运算 // 定义点结构 struct Point { double x, y; Point(double x_, double y_) : x(x_), y(y_) {} }; // 最小二乘法求圆心和半径 …...

linux arm系统烧录
1、打开瑞芯微程序 2、按住linux arm 的 recover按键 插入电源 3、当瑞芯微检测到有设备 4、松开recover按键 5、选择升级固件 6、点击固件选择本地刷机的linux arm 镜像 7、点击升级 (忘了有没有这步了 估计有) 刷机程序 和 镜像 就不提供了。要刷的时…...

04-初识css
一、css样式引入 1.1.内部样式 <div style"width: 100px;"></div>1.2.外部样式 1.2.1.外部样式1 <style>.aa {width: 100px;} </style> <div class"aa"></div>1.2.2.外部样式2 <!-- rel内表面引入的是style样…...

【Java_EE】Spring MVC
目录 Spring Web MVC 编辑注解 RestController RequestMapping RequestParam RequestParam RequestBody PathVariable RequestPart 参数传递 注意事项 编辑参数重命名 RequestParam 编辑编辑传递集合 RequestParam 传递JSON数据 编辑RequestBody …...
【python异步多线程】异步多线程爬虫代码示例
claude生成的python多线程、异步代码示例,模拟20个网页的爬取,每个网页假设要0.5-2秒完成。 代码 Python多线程爬虫教程 核心概念 多线程:允许程序同时执行多个任务,提高IO密集型任务(如网络请求)的效率…...
重启Eureka集群中的节点,对已经注册的服务有什么影响
先看答案,如果正确地操作,重启Eureka集群中的节点,对已经注册的服务影响非常小,甚至可以做到无感知。 但如果操作不当,可能会引发短暂的服务发现问题。 下面我们从Eureka的核心工作原理来详细分析这个问题。 Eureka的…...

初探Service服务发现机制
1.Service简介 Service是将运行在一组Pod上的应用程序发布为网络服务的抽象方法。 主要功能:服务发现和负载均衡。 Service类型的包括ClusterIP类型、NodePort类型、LoadBalancer类型、ExternalName类型 2.Endpoints简介 Endpoints是一种Kubernetes资源…...
代码随想录刷题day30
1、零钱兑换II 给你一个整数数组 coins 表示不同面额的硬币,另给一个整数 amount 表示总金额。 请你计算并返回可以凑成总金额的硬币组合数。如果任何硬币组合都无法凑出总金额,返回 0 。 假设每一种面额的硬币有无限个。 题目数据保证结果符合 32 位带…...
第7篇:中间件全链路监控与 SQL 性能分析实践
7.1 章节导读 在构建数据库中间件的过程中,可观测性 和 性能分析 是保障系统稳定性与可维护性的核心能力。 特别是在复杂分布式场景中,必须做到: 🔍 追踪每一条 SQL 的生命周期(从入口到数据库执行)&#…...
WebRTC从入门到实践 - 零基础教程
WebRTC从入门到实践 - 零基础教程 目录 WebRTC简介 基础概念 工作原理 开发环境搭建 基础实践 三个实战案例 常见问题解答 1. WebRTC简介 1.1 什么是WebRTC? WebRTC(Web Real-Time Communication)是一个支持网页浏览器进行实时语音…...