如何使用 Loadgen 来简化 HTTP API 请求的集成测试

news2024/11/25 21:51:20

引言

在编写 HTTP 服务的过程中,集成测试 1 是保证程序正确性的重要一环,如下图所示,其基本的流程就是不断向服务发起请求然后校验响应的状态和数据等:

在这里插入图片描述

为大量的 API 和用例编写测试是一件繁琐的工作,而 Loadgen 2 正是为了简化这一过程而设计的。

一个简单的测试

假定我们在 127.0.0.1:9100 端口监听了一个 Pizza 3 服务,现在我们通过如下配置来测试集合(collection)的创建:

# loadgen.yml
requests:
  - request:
      method: PUT
      url: 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: id
    type: sequence
requests:
  - request:
      method: PUT
      url: 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: id
    type: sequence
runner:
  # 检查返回值是否正常
  assert_error: true
  # 检查断言是否通过
  assert_invalid: true
requests:
  - request:
      method: PUT
      url: 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: id
    type: sequence
runner:
  assert_error: true
  assert_invalid: true
requests:
  - request:
      method: PUT
      url: http://127.0.0.1:9100/test_create_document_$[[id]]
    assert:
      equals:
        _ctx.response.body_json.success: true
    register:
      # 把响应体的 collection 字段赋值给 $[[collection]]
      - collection: _ctx.response.body_json.collection
  - request:
      method: POST
      # 在上个请求创建的集合里添加一个文档
      url: http://127.0.0.1:9100/$[[collection]]/_doc
      body: '{"hello": "world"}'
    assert:
      equals:
        _ctx.response.body_json.result: created

上述示例中,我们利用动态注册的变量记录了每次测试创建的集合以便于后续请求使用。

最后的优化

为了使我们的配置更加灵活和“便携”,我们可以用环境变量来替换一些硬编码的值:

# loadgen.yml
variables:
  - name: id
    type: sequence
runner:
  assert_error: true
  assert_invalid: true
requests:
  - request:
      method: PUT
      # 读取 PIZZA_SERVER 这个环境变量
      url: $[[env.PIZZA_SERVER]]/test_create_document_$[[id]]
    assert:
      equals:
        _ctx.response.body_json.success: true
    register:
      - collection: _ctx.response.body_json.collection
  - request:
      method: POST
      url: $[[env.PIZZA_SERVER]]/$[[collection]]/_doc
      body: '{"hello": "world"}'
    assert:
      equals:
        _ctx.response.body_json.result: created

这样就可以通过:

PIZZA_SERVER=http://127.0.0.1:9101 loadgen -config loadgen.yml

在不同的 Pizza 服务上运行测试。


  1. https://en.wikipedia.org/wiki/Integration_testing ↩︎

  2. https://www.infinilabs.com/docs/latest/gateway/getting-started/benchmark ↩︎

  3. https://www.infinilabs.com/en/docs/latest/pizza ↩︎

  4. https://www.infinilabs.com/docs/latest/gateway/getting-started/benchmark#变量的使用 ↩︎

  5. https://www.infinilabs.com/docs/latest/gateway/getting-started/benchmark#返回值判断 ↩︎

  6. https://www.infinilabs.com/docs/latest/gateway/getting-started/benchmark#动态变量注册 ↩︎

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1176066.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

-- Could NOT find livox_ros_driver (missing: livox_ros_driver_DIR)

原因 缺少livox_ros_driver 包 解决办法如下 livox_ros_driver 地址 https://github.com/Livox-SDK/livox_ros_driver 下载下来放入ros的工作目录

pyspark连接mysql数据库报错

使用pyspark连接mysql数据库代码如下 spark_conf SparkConf().setAppName("MyApp").setMaster("local")spark SparkSession.builder.config(confspark_conf).getOrCreate()url "jdbc:mysql://localhost:3306/test?useUnicodetrue&characterE…

嵌套合并视频:高效技巧,让您成为视频剪辑大师

随着数字媒体的普及&#xff0c;视频剪辑已经成为一项必备的技能。在众多视频剪辑技巧中&#xff0c;嵌套合并视频是一项核心技能&#xff0c;它可以将多个视频片段合并成一个完整的视频。本文将介绍一些高效技巧&#xff0c;帮助您轻松掌握嵌套合并视频的方法&#xff0c;成为…

Excel中截取特殊字符之前、之间、之后的数据

1、第一个数据&#xff0c;“*” 之前的数据&#xff0c; 公式 &#xff1a;LEFT(J2,FIND("*",J2)-1) 2、第二个数据&#xff0c;两个 “*” 之中的数据&#xff0c; 公式 &#xff1a;MID(J2,FIND("*",J2)1,FIND("*",J2,FIND("*",…

vue项目npm install报错解决

一、报错信息 node-sass4.14.1 postinstall: node scripts/build.js 二、解决方式 &#xff08;1&#xff09;删除未成功安装的 node_modules 文件&#xff1b; &#xff08;2&#xff09;为 node-sass 单独设置镜像源&#xff1b; npm config set sass_binary_sitehttps:/…

构建数字孪生的四大挑战

如果不能解决由数字孪生带来的开发难题&#xff0c;那么企业就无法享受这种技术便利。 数字孪生已经成为企业当前面对的一大机遇&#xff0c;其核心在于利用虚拟副本中的分析数据对未来业务事件开展预测。这不仅能够大大降低决策难度&#xff0c;同时也有助于提升决策效果。 然…

即拼七人团模式让传统企业快速拥有百万用户

​小编介绍&#xff1a;10年专注商业模式设计及软件开发&#xff0c;擅长企业生态商业模式&#xff0c;商业零售会员增长裂变模式策划、商业闭环模式设计及方案落地&#xff1b;扶持10余个电商平台做到营收过千万&#xff0c;数百个平台达到百万会员&#xff0c;欢迎咨询。 七人…

特征漂移指标 PSI

特征漂移指标 PSI 背景描述 稳定性指的是参与对比两者相同指标差异性很小。机器学习使用训练数据&#xff08;训练集和验证集&#xff09;建模&#xff0c;使用测试数据模拟生产环境数据测试模型结果&#xff0c;其建模的假设是&#xff1a;训练数据涵盖了该问题所有的案例数…

(附源码)基于springboot鲜花商城小程序-计算机毕设 84731

基于springboot微信小程序的鲜花商城 摘 要 随着我国经济迅速发展&#xff0c;人们对手机的需求越来越大&#xff0c;各种手机软件也都在被广泛应用&#xff0c;但是对于手机进行数据信息管理&#xff0c;对于手机的各种软件也是备受用户的喜爱&#xff0c;微信小程序的鲜花商…

Find My遥控器|苹果Find My技术与遥控器结合,智能防丢,全球定位

在日常生活中&#xff0c;遥控器是很重要的部分。使用遥控器去操作各种不同的设备&#xff0c;不仅可以省心和省力&#xff0c;同时还能有效增加效率。遥控器是一种无线发射装置&#xff0c;通过现代的数字编码技术&#xff0c;将按键信息进行编码&#xff0c;通过红外线二极管…

电子敲木鱼小程序源码系统 支持广告视频流量主 带完整搭建教程

大家好啊&#xff01;好久不见。今天罗峰来给大家分享一款电子敲木鱼小程序源码系统。相信大家都听说这个电子敲木鱼小程序&#xff0c;是当代年轻人缓解压力的一款小程序。今天罗峰就来给大家介绍一下他的功能&#xff0c;这款小程序自带广告视频流量&#xff0c;帮你轻松赚钱…

【C++】类与对象 上

前言 感觉自己的基础还是不够好 最近打算在学新知识的同时 把之前的一些知识点再复习一下 引入 在C语言的学习中 我们学习过结构体 我们用结构体来描述复杂的对象 在结构体中只能定义变量 而在C的结构体中 我们可以在C中 定义函数 下面给出一个简单的例子 创建一个结构体 并…

新一代存储介质技术SCM探讨

什么是SCM介质&#xff1f; SCM介质现状 SCM介质产品形态和在存储系统中的应用 高性能SSD 字节型DIMM形态 小结 什么是SCM介质&#xff1f; SCM&#xff08;Storage Class Memory&#xff09;是当前业界非常热门的新介质形态&#xff0c;同时具备持久化&#xff08;Storage Cla…

LangChain+LLM实战---Midjourney(v5.1) Prompt深度剖析

原文&#xff1a;Anatomy of Midjourney Promps: In-Depth Study for effective Prompting Strategies — V5.1 examples 作者&#xff1a;Michael King 你是否曾经发现自己盯着Midjourney的空白画布&#xff0c;手指悬停在键盘上&#xff0c;让我问自己&#xff1a;“我应该…

Python中最常用的10个内置函数!

更多资料获取 &#x1f4da; 个人网站&#xff1a;涛哥聊Python Python作为一种多用途编程语言&#xff0c;拥有丰富的内置函数库&#xff0c;这些函数可以极大地提高开发效率。本文将介绍Python中最常用的10个内置函数&#xff0c;它们的功能各有不同&#xff0c;但在实际编程…

【unity实战】实现类似英雄联盟的buff系统(附项目源码)

文章目录 先来看看最终效果前言开始BUFF系统加几个BUFF测试1. 逐层消失&#xff0c;升级不重置剩余时间的BUFF2. 一次性全部消失&#xff0c;升级重置剩余时间的BUFF3. 永久BUFF&#xff0c;类似被动BUFF4. 负面BUFF&#xff0c;根据当前BUFF等级计算每秒收到伤害值&#xff0c…

腾讯会议录制视频全攻略,让会议记录更轻松

随着远程办公和线上教学的兴起&#xff0c;腾讯会议已成为一种常见的在线会议工具&#xff0c;用于实现远程办公、在线教育和协作。然而&#xff0c;许多用户不知道如何记录这些重要的会议&#xff0c;特别是希望将其保留作为会议纪要或培训资料。在本文中&#xff0c;我们将探…

康耐视深度学习ViDi-Tool菜单介绍

Train 训练该工具中所有标注的图像 Process 处理该工具中所有的图像 Abort 中止当前训练或处理任务 Rename 更改当前工具的名称 Clone 克隆当前所选工具 Import导出当前所选工具 Export导入相对应的工具 Edit Models编辑工具中的模型 Update Parameters更新当前工具参数 工具菜…

CODESYS开发教程12-任务配置

今天继续我们的小白教程&#xff0c;老鸟就不要在这浪费时间了&#x1f60a;。 前面一期我们介绍了CODESYS的库管理器。这一期就来介绍一下CODESYS工程中“任务配置”的使用。看过前面教程的朋友可能记得&#xff0c;在工程的基本组成中有简单介绍过如何使用任务配置添加任务&…

Python中使用Tkinter和Difflib模块实现文本比对功能

目录 一、引言 二、Tkinter简介 三、Difflib简介 四、实现文本比对功能 五、代码展示 六、注意事项 总结 一、引言 在Python中&#xff0c;Tkinter和Difflib是两个非常实用的模块。Tkinter是Python的标准图形用户界面(GUI)库&#xff0c;可以用来创建桌面应用程序。Dif…