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}语法:

jmeter vars

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获取。


原始标题:How to Pass a Variable From One Thread Group to Another in JMeter | Baeldung