
本文详解如何在 Gatling 中通过 LinkedHashMap 有序组织多个 ChainBuilder 组,并使用嵌套 group(...).on(...) 正确构建 ScenarioBuilder,确保 Session 在各组间持续有效、属性可正常解析。
本文详解如何在 gatling 中通过 `linkedhashmap` 有序组织多个 chainbuilder 组,并使用嵌套 `group(...).on(...)` 正确构建 scenariobuilder,确保 session 在各组间持续有效、属性可正常解析。
在 Gatling 性能测试中,将用户行为划分为逻辑分组(如“登录组”“添加商品组”“查询组”)是提升脚本可维护性与可读性的常见做法。但若直接对 Map<String, ChainBuilder[]> 迭代调用 .group(...).on(exec(...)),极易因执行链断裂导致 Session 失效——后续 ChainBuilder 无法访问前序步骤设置的 session 属性(如 token、userId),从而引发 401 错误或 NPE。
根本原因在于:Gatling 的 ScenarioBuilder.exec() 是链式追加操作,而原始代码中每次 .group(...).on(...) 都试图在已有 scenarioBuilder 上“并列插入”新分组,但未正确包裹为单个可执行单元;更关键的是,exec(chainBuilders) 接收的是 ChainBuilder[] 数组,而 Gatling 3.9+ 推荐使用 List<ChainBuilder> 并配合 exec(...) 的变参重载,否则数组可能被错误解析为单个元素,造成执行跳过。
✅ 正确解法是:将每个分组封装为独立的 exec(group(...).on(...)) 单元,再统一注入主场景。以下是推荐实现:
protected ScenarioBuilder createScenario(GatlingScenario scenario) {
List<ChainBuilder> allSteps = new ArrayList<>();
// 使用 LinkedHashMap 保证执行顺序(如:登录 → 商品操作 → 查询)
LinkedHashMap<String, List<ChainBuilder>> groupChainMap = scenario.getGroupChainBuilderMap();
groupChainMap.forEach((groupName, chainList) -> {
// ✅ 关键:每个 group 必须作为独立 exec() 单元加入链表
allSteps.add(
exec(group(groupName).on(chainList.toArray(new ChainBuilder[0])))
);
});
return scenario(scenario.getScenarioName())
// 初始化全局 Session 属性(baseUrl、时间戳等)
.exec(session -> session.setAll(Map.of(
"timeStamp", LocalDateTime.now(),
"baseUrl", this.baseUrl
)))
// ✅ 批量执行所有已封装好的分组单元
.exec(allSteps);
}配套的数据结构需同步升级为泛型安全的 LinkedHashMap<String, List<ChainBuilder>>:
@AllArgsConstructor
@Getter
public class GatlingScenario {
private String scenarioName;
// 注意:必须是 LinkedHashMap 以保障执行顺序!
private LinkedHashMap<String, List<ChainBuilder>> groupChainBuilderMap;
}初始化示例(清晰、类型安全、顺序可控):
List<ChainBuilder> loginChainList = List.of(
LoginActions.doLogin,
PlanActions.doAdminLoginMain,
UserActions.doGetUserMetaData
);
List<ChainBuilder> addItemChainList = List.of(
ItemActions.doGetItem,
ItemActions.doGetItemSearch,
ItemActions.doAllItemSearch,
ItemActions.doGetItemById,
ItemActions.doAssignItemToUser
);
LinkedHashMap<String, List<ChainBuilder>> groupMap = new LinkedHashMap<>();
groupMap.put("Login Group", loginChainList);
groupMap.put("Add Item Group", addItemChainList);
GatlingScenario scenario = new GatlingScenario("E2E_User_Journey", groupMap);⚠️ 重要注意事项:
- 勿用 HashMap:其无序性会导致分组执行顺序不可控(如先执行“Add Item”再执行“Login”),必然失败;
- Session 传递是隐式的:Gatling 自动将上一个 ChainBuilder 的 Session 透传给下一个,只要它们处于同一 exec(...) 链内(本方案已确保);
- 避免在 group 内部重复 setSession:除非有特殊上下文隔离需求,否则应在顶层 exec(session -> ...) 统一初始化;
- 调试技巧:在关键 ChainBuilder 末尾添加 .exec(session -> { logger.info("Session keys: {}", session.getAllAttributes().keySet()); return session; }) 快速验证属性是否存在。
通过该模式,您不仅能稳定复用分组逻辑,还可轻松支持动态分组(如基于测试数据配置启用/跳过某组),真正实现高内聚、低耦合的 Gatling 脚本工程化实践。

















