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

Gatling基于配置生成断言异常:多场景断言复用同一请求名排查

Gatling断言构建异常问题排查

问题背景

正在编写Gatling仿真脚本,通过配置文件读取一组带属性的API信息,流程如下:

  • 读取配置获取n个活跃场景,通过CommonRequest类创建请求
  • 将请求通过CommonScenario构建为场景
  • 利用CommonScenario的属性生成注入配置

前三个步骤均正常,但基于CommonScenario属性构建断言时不符合预期。

代码片段

// get active scenarios from the config
val activeApiScenarios: List[String] = Utils.getStringListProperty("my.active_scenarios")


// build all active scenarios from config
var activeScenarios: Set[CommonScenario] = Set[CommonScenario]()
activeApiScenarios.foreach { scenario =>
  activeScenarios += CommonScenarioBuilder()
    .withRequestName(Utils.getProperty("my." + scenario + ".request_name"))
    .withRegion(Utils.getProperty("my." + scenario + ".region"))
    .withConstQps(Utils.getDoubleProperty("my." + scenario + ".const_qps"))
    .withStartQps(Utils.getDoubleListProperty("my." + scenario + ".toth_qps").head)
    .withPeakQps(Utils.getDoubleListProperty("my." + scenario + ".toth_qps")(1))
    .withEndQps(Utils.getDoubleListProperty("my." + scenario + ".toth_qps")(2))
    .withFeeder(Utils.getProperty("my." + scenario + ".feeder"))
    .withAssertionP99(Utils.getDoubleProperty("my." + scenario + ".p99_lte_assertion"))
    .build
}

// build population builder set by adding inject profile values to scenarios
var injectScenarios: Set[PopulationBuilder] = Set[PopulationBuilder]()
var assertions : Set[Assertion] = Set[Assertion]()

activeScenarios.foreach { scenario =>
  // create injection profiles from CommonScenarios
  injectScenarios += scenario.getCommonScenarioBuilder
    .inject(nothingFor(5 seconds),
      rampUsersPerSec(scenario.startQps).to(scenario.rampUpQps).during(rampOne seconds),
      rampUsersPerSec(scenario.rampUpQps).to(scenario.peakQps).during(rampTwo seconds),
      rampUsersPerSec(scenario.peakQps).to(scenario.rampDownQps) during (rampTwo seconds),
      rampUsersPerSec(scenario.rampDownQps).to(scenario.endQps).during(rampOne     seconds)).protocols(httpProtocol)

  // create scenario assertions this does not work for some reason
  assertions += Assertion(Details(List(scenario.requestName)), TimeTarget(ResponseTime, Percentiles(4)), Lte(scenario.assertionP99))
}

setUp(injectScenarios.toList)
  .assertions(assertions)

注:scenario.requestName直接来自构建好的场景,场景包含.feed(feederBuilder).exec(commonRequest)逻辑。

预期与实际现象

  • 预期:每个场景对应的断言能被正确构建并传入setUp()
  • 实际现象:打印断言时,所有断言复用同一个Request Name,仅Lte值不同(配置了12个API,各有不同名称和阈值),仿真后所有断言结果均为false。

问题分析与解决方案

核心问题:CommonScenario类的equals/hashCode实现缺陷

你使用Set[CommonScenario]存储构建好的场景,但如果CommonScenario类没有基于关键属性正确实现equals和hashCode方法,Set会误判多个不同实例为同一对象,最终Set中只会保留最后一个场景实例。遍历Set时所有迭代都复用该实例,导致断言的requestName全部重复。

验证方式

构建完activeScenarios后打印其大小,若实际大小远小于配置的12个,即可确认是此问题。

修复方案

  1. 改用Case Class:将CommonScenario定义为Scala的case class,case class会自动基于所有成员属性生成正确的equals和hashCode方法,避免Set去重错误:

    case class CommonScenario(
      requestName: String,
      region: String,
      constQps: Double,
      startQps: Double,
      peakQps: Double,
      endQps: Double,
      feeder: String,
      assertionP99: Double
      // 其他必要属性
    )
    

    对应的Builder类也需要基于此case class构建实例。

  2. 替换集合类型:将Set[CommonScenario]改为List[CommonScenario],List不会自动去重,能完整保留所有构建的场景实例,规避equals/hashCode带来的问题。

额外验证点

修复实例存储问题后,需确认scenario.requestName与commonRequest中设置的请求名称完全一致(包括大小写、空格等),Gatling断言采用精确匹配,名称不匹配会导致断言结果异常。

方案可行性

该整体方案是可行的,解决场景实例存储问题后,每个场景对应独立断言的逻辑就能正常运行。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 07:15:33