1. 引言
本文将探讨在JMeter中如何在线程组之间共享变量。当某个线程组执行设置任务(如认证或数据准备),而其他线程组需要使用其结果时,这种需求非常常见。
由于JMeter变量默认是线程局部的,我们将介绍几种简单且健壮的技术来实现跨线程组数据传递。
2. 场景与设置
我们的测试场景包含两个操作:
- 向接口POST数据,获取返回的UUID
- 使用该UUID通过GET请求检索已提交的数据
我们将这些操作拆分到两个线程组中:
- 第一个线程组处理POST请求并存储返回的UUID
- 第二个线程组使用存储的UUID执行GET请求
2.1 创建设置线程组
由于JMeter默认并发执行线程组,我们需要使用特殊线程组类型来控制执行顺序。
右键点击测试计划,选择:
添加 -> 线程(用户) -> setUp 线程组
这确保了设置逻辑(即POST请求和变量保存)在其他线程组开始前执行。
2.2 提交随机数据
为提交随机测试数据,我们使用HTTP请求元素配合${__RandomString(5)}
:
在所有方案中,我们将在POST请求后使用JSR223后置处理器提取响应文本并跨线程组共享。 然后在GET请求前使用JSR223前置处理器获取保存的响应值。特别注意:所有脚本均使用Java语言编写。
2.3 理解JMeter上下文变量
在JMeter组件(如采样器、前置/后置处理器)中可访问内置脚本变量。本教程主要使用:
prev
:前一个采样器的SampleResult(通常是HTTP请求),用于提取响应体和状态码props
:JMeter Properties对象,全局共享,适合跨线程/线程组传递值vars
:当前线程的JMeter变量,用于读写值(可通过${}
语法访问)
3. 使用JMeter Properties
跨线程组共享值的最简单方法是使用props
。这些属性在整个测试执行期间全局共享且持久存在:
String response = prev.getResponseDataAsString();
props.put("uuid", response);
注意props
是Object类型映射,不限于String值。然后在其他线程组中检索并存入vars
:
String uuid = props.get("uuid");
vars.put("uuid", uuid);
存入vars
后,即可在HTTP请求或其他测试元素中使用${uuid}
语法:
Properties在所有线程和线程组间共享,适用于单值传递或设置线程组仅使用单线程的场景。对于更复杂的协调需求,我们来看其他方案。
4. 使用bsh.shared命名空间
更灵活(但较旧)的方案是使用BeanShell共享命名空间bsh.shared
,它相当于测试计划中所有BeanShell脚本共享的全局对象存储。此技术适合共享复杂数据结构(如队列或映射)。
创建新变量uuidQueue
。通过比较void
检查是否已定义,然后初始化为LinkedList:
String response = prev.getResponseDataAsString();
if (bsh.shared.uuidQueue == void) {
bsh.shared.uuidQueue = new LinkedList();
}
然后正常添加元素:
bsh.shared.uuidQueue.add(response);
在其他线程组中检索:
String uuid = bsh.shared.uuidQueue.poll();
vars.put("uuid", uuid);
⚠️ 注意:BeanShell被认为比Groovy或纯Java脚本性能更差且安全性较低。
5. 文件读写方案
当需要运行间可见性或持久化时,文件通信是可行的选择(尽管更繁琐)。本例中使用ctx.getThreadNum()
按线程号创建独立文件:
String response = prev.getResponseDataAsString();
File file = new File("/tmp/shared-file" + ctx.getThreadNum() + ".txt");
标准文件写入模板:
try {
FileWriter writer = new FileWriter(file);
writer.write(response);
writer.close();
} catch (IOException e) {
log.error("Failed to write file", e);
}
最终读取文件:
File file = new File("/tmp/shared-file" + ctx.getThreadNum() + ".txt");
try {
Scanner reader = new Scanner(file);
String uuid = reader.hasNextLine() ? reader.nextLine().trim() : "";
reader.close();
vars.put("uuid", uuid);
} catch (IOException e) {
log.error("Failed to read file", e);
}
✅ 优点:
- 便于调试、持久化或运行间手动操作
- 对大数据集或批量导出更安全
❌ 缺点:
- 磁盘I/O导致性能下降
- 需谨慎管理文件清理和线程特定路径
6. 总结
本文探讨了JMeter中跨线程组传递数据的几种技术:
- JMeter Properties:适合简单的单值共享
- bsh.shared:适用于高级场景(如按线程队列),尽管较旧
- 文件方案:提供更大灵活性,适合需要持久化的场景
源代码可在GitHub获取。