为了账号安全,请及时绑定邮箱和手机立即绑定

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

标签:
性能测试

引言

在编写 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

点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消