You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Gatling不同类的ChainBuilder间传递收集的变量

Gatling跨测试类传递会话变量的解决方案

核心问题本质

Gatling的会话对象是用户绑定、线程隔离的,每个虚拟用户拥有独立会话,跨类直接访问其他用户的会话必然无效;而跨场景默认不共享会话,所以你当前用andThen串联场景的方式,仅能保证场景执行顺序,但无法直接传递单个用户的会话变量。

可行解决方案

1. 将相关Chain合并到同一个场景(推荐)

这是最直接的方案,让同一个虚拟用户的会话贯穿两个Chain,自然就能访问到之前保存的变量。

示例代码:

// BooksStore类
class BooksStore {
  val fetchFirstBookId: ChainBuilder = exec(http("Get Book List")
    .get("/api/books")
    .check(jsonPath("$[0].id").saveAs("firstBookId")))
}

// Client类
class Client {
  val queryBookDetail: ChainBuilder = exec(http("Get Book Detail")
    .get("/api/books/${firstBookId}"))
}

// Simulation类
class BookFlowSimulation extends Simulation {
  val booksStore = new BooksStore()
  val client = new Client()

  // 同一个场景中先后执行两个Chain,共享同一用户会话
  val bookScenario = scenario("End-to-End Book Flow")
    .exec(booksStore.fetchFirstBookId)
    .exec(client.queryBookDetail)

  setUp(bookScenario.inject(atOnceUsers(5)))
}

2. 跨场景传递全局共享数据(适合静态/唯一数据)

如果需要在不同场景间传递全局唯一的数据(比如系统中第一个图书ID,所有后续用户都用这个值),可以用线程安全的全局存储:

// 全局共享对象,用线程安全容器保证多线程环境下的数据一致性
object SharedBookData {
  private val bookIdHolder = new java.util.concurrent.ConcurrentHashMap[String, String]()

  def setFirstBookId(id: String): Unit = bookIdHolder.put("firstBookId", id)
  def getFirstBookId: Option[String] = Option(bookIdHolder.get("firstBookId"))
}

// BooksStore类
class BooksStore {
  val fetchAndStoreBookId: ChainBuilder = exec(http("Get Book List")
    .get("/api/books")
    .check(jsonPath("$[0].id").saveAs("firstBookId")))
    .exec(session => {
      val bookId = session("firstBookId").as[String]
      SharedBookData.setFirstBookId(bookId)
      session
    })
}

// Client类
class Client {
  val useGlobalBookId: ChainBuilder = exec(session => {
    SharedBookData.getFirstBookId match {
      case Some(id) => session.set("firstBookId", id)
      case None => session.markAsFailed // 处理数据未准备好的情况
    }
  })
  .exec(http("Query Book Detail")
    .get("/api/books/${firstBookId}"))
}

// Simulation类
class CrossScenarioSimulation extends Simulation {
  val booksStore = new BooksStore()
  val client = new Client()

  val fetchScenario = scenario("Fetch Global Book Id").exec(booksStore.fetchAndStoreBookId)
  val queryScenario = scenario("Use Global Book Id").exec(client.useGlobalBookId)

  // 用andThen保证第一个场景执行完成后,再启动第二个场景
  setUp(fetchScenario.inject(atOnceUsers(1)) andThen queryScenario.inject(atOnceUsers(10)))
}

3. 用Feeder批量传递数据(适合多组复用数据)

如果需要收集一组数据供后续场景使用,可以先将数据导出到文件,再用Feeder加载:

// BooksStore类:收集数据并写入文件
class BooksStore {
  val exportBookIds: ChainBuilder = exec(http("Get All Books")
    .get("/api/books")
    .check(jsonPath("$[*].id").findAll.saveAs("bookIds")))
    .exec(session => {
      val bookIds = session("bookIds").as[List[String]]
      val writer = new java.io.PrintWriter("book_ids.csv")
      writer.println("bookId")
      bookIds.foreach(id => writer.println(id))
      writer.close()
      session
    })
}

// Client类:从Feeder读取数据
class Client {
  val bookIdFeeder = csv("book_ids.csv").circular

  val queryWithFeeder: ChainBuilder = feed(bookIdFeeder)
    .exec(http("Query Book Detail")
    .get("/api/books/${bookId}"))
}

// Simulation类
class FeederBasedSimulation extends Simulation {
  val booksStore = new BooksStore()
  val client = new Client()

  val exportScenario = scenario("Export Book Ids").exec(booksStore.exportBookIds)
  val queryScenario = scenario("Query Books from Feeder").exec(client.queryWithFeeder)

  setUp(exportScenario.inject(atOnceUsers(1)) andThen queryScenario.inject(rampUsers(20).during(10)))
}

避坑提醒

  • 不要尝试用普通类的成员变量存储会话值:Gatling的测试代码是初始化一次后多线程运行,成员变量会被所有用户共享,导致数据混乱。
  • 跨场景传递用户专属会话变量:这种场景不存在合理的实现方式,因为每个用户的会话是独立的,跨场景意味着不同用户实例,会话无法共享。

内容的提问来源于stack exchange,提问作者Razvan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 09:35:27