首页 > 其他分享 >如何使用 Loadgen 来简化 HTTP API 请求的集成测试

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

时间:2023-11-06 10:58:22浏览次数:30  
标签:127.0 HTTP Loadgen 0.1 create API test http document

引言

在编写 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#动态变量注册 ↩︎

标签:127.0,HTTP,Loadgen,0.1,create,API,test,http,document
From: https://www.cnblogs.com/infinilabs/p/17812056.html

相关文章

  • WebApi入门
    1.怎么理解webapi可以把他看作一个仓库,负责接收货物和出口货物只是一个地址MVC访问展示的是一个页面webapi访问地址是拿到一个数据2.webapi接口地址从何而来新建一个webapi项目,启动这是线程为我们提供的地址请求了这个地址,返回了一串数据https://localhost:5001/W......
  • fatal: unable to access 'https://github.com/wolfcw/libfaketime.git/': Encountere
    您遇到的问题可能是网络问题或与`git`配置有关。以下是一些建议的解决步骤:1.**检查网络连接**:确保您的服务器/计算机可以正常访问外部网站。您可以尝试使用`ping`或`curl`来检查网络连接。 ```bash pinggithub.com ```2.**使用HTTP代替HTTPS**:尝试使用HTTP代替HTT......
  • face-api基于tensorflow 的人像检测npm 包
    face-api基于tensorflow的人像检测npm包,原始项目为justadudewhohacks/face-api.js但是因为缺少维护,社区有人自己fork了一个新的vladmandic/face-api,可以更好的支持tensorflow新版本,当然很不错还可以支持基于wasm的backend(@tensorflow/tfjs-backend-wasm)参考使用demo.......
  • Java系列:Java8 新特性:强大的 Stream API(创建 Stream、中间操作、终止操作)
    Java8中有两大最为重要的改变。第一个是Lambda表达式;另外一个则是StreamAPI。StreamAPI(java.util.stream)把真正的函数式编程风格引入到Java中。这是目前为止对Java类库最好的补充,因为StreamAPI可以极大提供Java程序员的生产力,让程序员写出高效率、干净、简洁的代码。......
  • Java21对虚拟线程进行http压测使用不同的GC
    JDK21默认GC是G1.JDK21除了G1外,还可以使用ZGC(Java11预览、Java15正式版),Java21在ZGC基础上继续推出了分代ZGC,目前还是试行阶段。开启ZGC:java-XX:+UseZGC-jarmyapp.jar开启ZGC,并试用分代ZGCjava-XX:+UseZGC-XX:+ZGenerational-jarmyapp.jar以下的对一个启用tomcat......
  • Kubernetes:kube-apiserver 和 etcd 的交互
    kubernetes:kube-apiserver系列文章:Kubernetes:kube-apiserver之scheme(一)Kubernetes:kube-apiserver之scheme(二)Kubernetes:kube-apiserver之启动流程(一)Kubernetes:kube-apiserver之启动流程(二)0.前言上几篇文章介绍了kubernetes的核心数据结构scheme......
  • 小程序性能提速大作战:少点HTTP请求,多点性能!
    引言:嗨,各位小程序魔法师们,是不是常常被小程序的加载速度拖拖拉拉?别担心,小编今天要带你们探讨一项神奇的技能——减少HTTP请求,让你的小程序速度飙升!我们要玩得开心,一切都要如丝滑般流畅!背景:小程序性能提速的关键之一就是减少HTTP请求。过多的请求会导致小程序的加载速度变得缓慢,影......
  • redhat --修改时区 转发 https://www.cnblogs.com/rongren/p/12600869.html
    LINUXredhat修改时间 在LINUX系统中,时间分为两个部分,一个是系统时间,只针对运行时,重启后就无用,二是主板时间,系统重启后,自动从主板中获取时间。一、查看时间  date命令:查看当前时间二、修改时间 时间修改有两种方法(一)修改系统时间,然后执行命令从系统同步时间 1、......
  • 使用FastAPI部署Ultralytics YOLOv5模型
    前言 YOLO是YouOnlyLookOnce(你只看一次)的缩写,它具有识别图像中的物体的非凡能力,在日常应用中会经常被使用。所以本文将介绍如何使用FastAPI的集成YOLOv5,这样我们可以将YOLOv5做为API对外提供服务。本文转载自DeephubImba作者:auliyafirdaus仅用于学术分享,若侵权请联系删......
  • 在Vue 3中如何在created钩子中进行API调用?
    在Vue3中,您可以使用setup函数来替代Vue2中的created生命周期钩子,并在其中进行API调用。下面是一个示例:import{ref,onMounted}from'vue'importaxiosfrom'axios'exportdefault{setup(){//创建一个响应式变量来存储API的返回数据constdata=ref(null......