3. 测试脚本开发
好,咱们进入实战环节。脚本开发这块,说白了就是把你脑子里的压测场景,翻译成工具能听懂的语言。我个人习惯把脚本开发分成三个层次:先能跑,再能复用,最后能自动验证。今天咱们就按这个路子来。
核心观点:一个优秀的压测脚本,不是写出来就完事了。它要能应对不同环境、不同数据、不同业务组合。我见过太多团队,每次压测都重写脚本,那效率太低了。
3.1 脚本结构设计:从单线程到可复用
先说说脚本的整体骨架。我一般会把脚本拆成三块:初始化块、业务块、清理块。
- 初始化块:放全局变量、默认参数、连接配置。这部分只跑一次。
- 业务块:真正的压测逻辑。登录、查询、下单、支付,按顺序放好。
- 清理块:释放资源、关闭连接、清理测试数据。
为什么要这么分?你想想看,如果每次压测都要重新登录,那登录接口的压力会非常大,反而掩盖了真正要测的业务接口。我在项目中遇到过这种情况,一开始没注意,结果压测报告出来,登录接口的TPS比业务接口还高,领导一看就懵了。
嗯,这里要注意:初始化块和清理块不要放在事务控制器里。它们不计入压测结果。
3.2 参数化:让脚本活起来
参数化是脚本复用的基础。说白了,就是把硬编码的值变成变量。我常用的参数化方式有四种:
| 方式 | 适用场景 | 我的建议 |
|---|---|---|
| CSV数据文件 | 大量用户数据、商品ID | 最常用,注意文件编码 |
| 函数助手 | 随机数、时间戳、UUID | 适合生成唯一标识 |
| 用户自定义变量 | 全局配置、环境切换 | 配合属性传递更灵活 |
| 数据库结果集 | 从数据库动态获取数据 | 性能开销大,慎用 |
举个例子,压测一个商品详情页。你不能让所有虚拟用户都看同一个商品吧?那样缓存一命中,结果就失真了。我一般会准备一个商品ID的CSV文件,里面放几千个真实商品ID,让每个用户随机取一个。
// CSV文件内容示例
// product_ids.csv
10001,10002,10003,10004,10005
// 在JMeter中配置CSV Data Set Config
// 变量名:productId
// 共享模式:所有线程
小技巧:CSV文件的行数最好大于虚拟用户数。如果不够,可以设置循环模式为「遇到EOF再次循环」。但要注意,这样可能会导致数据重复,影响结果准确性。
3.3 关联:把接口串起来
关联是压测脚本里最容易出问题的地方。为什么?因为很多新手不知道,接口之间是有依赖关系的。比如,你要下单,必须先拿到用户的和商品的库存ID。
我常用的关联手段有两种:正则表达式提取器和JSON提取器。我个人更推荐JSON提取器,因为现在大部分接口返回的都是JSON格式,解析起来更直观。
// 假设登录接口返回如下JSON
{
"code": 0,
"data": {
"": "abc123xyz",
"userId": 88888
}
}
// JSON提取器配置
// 变量名:
// JSON表达式:$.data.
// 匹配编号:1
关联的坑在哪里?我曾经遇到过一个情况:登录接口返回的有时效性,但脚本里没做刷新逻辑。结果压测跑了半小时后,所有请求都返回401。嗯,这里要记住:关联的值一定要考虑有效期。如果过期,脚本里要加一个判断,自动重新登录。
避坑指南:我曾经在压测一个支付流程时,关联了一个订单号。但订单号生成规则里包含了时间戳,导致每次请求的订单号都不一样。结果断言一直失败。后来发现,是关联的表达式写错了,匹配到了多个值。记住:关联一定要用「调试取样器」先验证一下提取的值对不对。
3.4 断言:让脚本自己会检查
断言是压测脚本的「质检员」。没有断言的压测,就像闭着眼睛开车——你以为跑得挺快,其实早就跑偏了。
我常用的断言类型:
- 响应断言:检查返回的状态码、响应文本。最基础,但够用。
- JSON断言:检查JSON里的某个字段值。适合接口返回结构固定的场景。
- 大小断言:检查响应数据的大小。适合判断是否返回了完整数据。
- 持续时间断言:检查响应时间是否超过阈值。这个我特别喜欢用,能直接发现慢接口。
举个例子,压测一个查询接口。正常返回的数据里,data.list 应该是一个数组,长度大于0。如果返回空数组,说明查询条件有问题。这时候用JSON断言检查 $.data.list.length 是否大于0,就能快速发现问题。
// JSON断言配置示例
// 断言字段:$.code
// 预期值:0
// 类型:等于
// 再加一个断言
// 断言字段:$.data.list.length
// 预期值:1
// 类型:大于
我的习惯:每个关键接口至少加两个断言。一个检查业务状态码,一个检查关键数据字段。这样既能发现接口挂了,也能发现接口返回了错误数据。
3.5 监听器配置:别让数据白跑
监听器是压测的「仪表盘」。没有监听器,你跑完压测都不知道结果怎么样。但监听器也不能乱加,加多了会影响压测本身的性能。
我一般这样配置:
- 压测过程中:只开一个「聚合报告」和一个「图形结果」。够用,不占资源。
- 调试阶段:开「查看结果树」和「调试取样器」。方便定位问题。
- 压测结束后:用「简单数据写入器」把结果存成CSV文件。方便后续分析。
这里有个误区:很多人喜欢在压测时开着「查看结果树」。你想想看,每个请求的响应数据都要存到内存里,还要渲染到界面上,这得消耗多少资源?我见过一个团队,压测1000并发,结果「查看结果树」直接撑爆了内存。
注意:监听器的配置要跟压测场景匹配。如果是长时间压测(比如8小时稳定性测试),建议只保留「简单数据写入器」,其他监听器全部关掉。等压测结束后,再用工具分析CSV文件。
3.6 实战案例:一个完整的压测脚本
说了这么多,咱们来个完整的例子。假设要压测一个电商的「搜索-详情-加购-下单」流程。
// 脚本结构
// 1. 初始化块(只跑一次)
// - 设置全局变量:baseUrl、env
// - 读取CSV文件:用户数据、商品数据
// 2. 业务块(循环执行)
// - 登录(关联)
// - 搜索商品(参数化关键词)
// - 查看商品详情(关联商品ID)
// - 加入购物车(参数化数量)
// - 提交订单(关联订单号)
// - 支付(断言检查支付状态)
// 3. 清理块(只跑一次)
// - 退出登录
// - 清理测试数据
这个脚本里,参数化用到了CSV文件(用户数据、商品关键词),关联用到了JSON提取器(、商品ID、订单号),断言用到了响应断言和JSON断言。监听器只开了聚合报告和简单数据写入器。
嗯,这里有个细节:每个接口之间要加一个「思考时间」。我用的是「固定定时器」,设置300-500毫秒。为什么?因为真实用户不会连续点击,中间会有停顿。不加思考时间,压测出来的TPS会虚高,跟线上表现对不上。
总结一下:脚本开发的核心就四个字——可复用、可验证。参数化让脚本能应对不同数据,关联让脚本能串联业务,断言让脚本能自我检查,监听器让结果能落地分析。把这四点做好,你的压测脚本就能从「一次性工具」变成「可复用的资产」。
好了,脚本开发这块就聊到这儿。记住:好的脚本是改出来的,不是写出来的。第一次跑通只是开始,后面要根据压测结果不断优化参数化策略、调整断言阈值、精简监听器配置。这才是压测脚本开发的常态。