测试动态 / 测试知识 / Gatling的随机性与真实性模拟:使用Random、Feeder与循环实现真实用户行为
Gatling的随机性与真实性模拟:使用Random、Feeder与循环实现真实用户行为
2026-01-13 作者:cwb 浏览次数:8

Gatling模拟真实用户行为是抛弃固定脚本,引入随机性、动态数据和非固定节奏。这主要通过 Random、Feeder 和循环控制来实现。


Random注入不确定性

Gatling的Random对象是模拟用户操作随机性。


随机等待时间

真实用户在操作间会有停顿,Gatling通过pause结合Random来模拟。


scala

import scala.concurrent.duration._


// 1. 固定范围均匀分布:在2到5秒之间随机暂停(单位默认秒)

pause(2, 5)


// 2. 更专业的指定分布:使用Random对象生成

pause(Random.nextInt(5).seconds) // 0-4秒随机整数秒

pause(Random.nextDouble(5).seconds) // 0.0-5.0秒随机浮点数秒

pause(Random.nextGaussian(10, 2).seconds) // 均值10秒,标准差2秒的正态分布


建议:对于浏览列表页等情形,使用 uniform;对于“思考时间”这种集中在一定范围内的,可使用 normal;exponential 可用于模拟某些等待事件。


随机选择

模拟用户非固定的操作途径。


scala

import scala.util.Random


// 1. 随机选择一项:从序列中随机选一个

val randomSearchKeyword = Random.shuffle(List("手机", "电脑", "平板", "耳机")).head

exec(http("Search_${keyword}")

  .get("/search")

  .queryParam("q", randomSearchKeyword))


// 2. 按权重随机选择(随机决定树):模拟30%的用户点击详情,70%继续浏览

randomSwitch(

  30.0 -> exec(http("View_Detail").get("/detail/${productId}")),

  70.0 -> exec(http("Continue_Browsing").get("/list?page=${nextPage}"))

)


Feeder数据驱动和用户身份多样化

Feeder是为每个虚拟用户提供独特、真实测试数据的机制。


Feeder类型和选择方法


CSV Feeder:csv("users.csv").circular,从CSV读取,circular(循环用)、random(随机用)、queue(用完失败)。最常用。

JSON Feeder:jsonFile("data.json").random,读取JSON,适合嵌套数据结构。

JDBC Feeder:jdbcFeeder(...),从数据库直接读取,数据最新但可能给数据库加压。

Array/Map Feeder:Array(Map("foo"->"bar")).random,直接在代码中定义小型数据集,灵活。

内联JSON:jsonUrl("""[{"id":1}]""").random,测试脚本内嵌数据,无需外部文件。


用法和性能优化


scala

// 1. 数据转换和清洗:在Feeder链中即时处理数据

val cleanUserFeeder = csv("users.csv")

  .transform { case (key, value) =>

    if (key == "email") (key, value.toLowerCase) else (key, value)

  }

  .circular


// 2. 组合Feeder:合并用户身份数据和业务数据

val combinedFeeder = csv("users.csv").random

  .and(jsonFile("products.json").random)


// 3. 【重点优化】共享Feeder和解耦:在Simulation顶层定义,避免重复读取

object Feeders {

  val sharedProductFeeder = csv("products.csv").circular

}

class MySimulation extends Simulation {

  val scn = scenario("Scenario")

    .feed(Feeders.sharedProductFeeder) // 所有情形共享同一数据源

    .exec(...)

}


循环创建动态用户会话流

循环控制操作序列的重复执行方式,是模拟用户不断交互的重点。


1. 基础循环


scala

// 1. 固定次数循环:重复执行5次搜索操作

repeat(5) {

  exec(http("Search").get("/search?q=test"))

  .pause(1)

}


// 2. 使用动态变量控制循环:每个用户的循环次数不同(从Session中取)

repeat("${desiredLoopCount}") { // 从Feeder或前置操作中获取变量

  exec(...)

}


2. 高级循环和退出条件


scala

// 1. 条件循环(while):模拟用户“刷到满意为止”的行为

asLongAs(session => session("hasFoundTarget").as[Boolean] == false) {

  exec(http("Next_Page").get("/list?page=${nextPage}"))

  .pause(2)

  // 需要在此循环内部的某个操作中,可能将 hasFoundTarget 设置为 true

  .exec(session => session.set("hasFoundTarget", Random.nextBoolean())) // 示例:随机决定是不是找到

}


// 2. 时间条件循环(during):模拟用户在固定时间段内的不断活动(如1分钟内不断操作)

during(1 minute) { // 重点:during块内的执行总时间会被控制

  exec(http("Do_Something").get("/api"))

  .pause(Random.nextInt(5).seconds) // 每次操作后随机等待

  // 注意:整个during块的时长 = 内部所有exec和pause时间的总和,直到达到1分钟

}


// 3. 永远循环(forever):模拟长时间在线的用户,一般配合 exitHereIfFailed 使用

forever {

  exec(http("Polling").get("/notifications"))

  .pause(5 seconds)

  .exitHereIfFailed // 如果轮询失败,则此虚拟用户退出

}


实战模拟电商用户行为

一个融合了上述所有概念的完整示例,模拟一个电商用户从登录到下单的真实、非固定行为。


scala

import scala.concurrent.duration._

import io.gatling.core.Predef._

import io.gatling.http.Predef._

import scala.util.Random


class AdvancedEcommerceSimulation extends Simulation {


  // --- 1. 定义Feeder ---

  // 用户账户数据

  val userFeeder = csv("data/users.csv").circular

  // 商品数据,随机使用

  val productFeeder = csv("data/products.csv").random

  // 搜索重点词,随机使用

  val keywordFeeder = Array(

    Map("keyword" -> "iPhone"),

    Map("keyword" -> "MacBook"),

    Map("keyword" -> "AirPods")

  ).random


  val httpProtocol = http.baseUrl("https://api.zmtests.com")


  // --- 2. 定义情形行为链 ---

  val scn = scenario("Realistic E-commerce User")

    // A. 用户登录:每个虚拟用户从Feeder获取唯一身份

    .feed(userFeeder)

    .exec(

      http("Login")

        .post("/login")

        .formParam("username", "${username}")

        .formParam("password", "${password}")

        .check(status.is(200))

        .check(jsonPath("$.token").saveAs("authToken")) // 保存token供后续使用

    )

    .pause(Random.nextInt(3).seconds) // 登录后随机短暂停留


    // B. 浏览行为:随机循环浏览多个页面

    .repeat(Random.nextInt(3) + 1) { // 浏览1-3个页面

      feed(keywordFeeder)

      .exec(

        http("Search Product")

          .get("/search")

          .queryParam("q", "${keyword}")

          .header("Authorization", "Bearer ${authToken}")

          .check(jsonPath("$.products[0].id").optional.saveAs("firstProductId"))

      )

      .pause(Random.nextDouble(2, 5).seconds) // 浏览搜索结果随机时间


      // 随机决定:是不是查看第一个商品详情?

      .randomSwitch(

        40.0 -> exec( // 40%的概率查看详情

          http("View Product Detail")

            .get("/product/${firstProductId}")

            .header("Authorization", "Bearer ${authToken}")

            .pause(Random.nextInt(4).seconds)

        ),

        60.0 -> exec { session => session } // 60%的概率跳过,什么都不做

      )

    }


    // C. 模拟加购到下单:使用条件循环,模拟可能放弃的行为

    .feed(productFeeder)

    .exec(

      http("Add to Cart")

        .post("/cart")

        .header("Authorization", "Bearer ${authToken}")

        .body(StringBody("""{"productId": "${productId}", "quantity": 1}"""))

        .asJson

    )

    .pause(Random.nextGaussian(10, 3).seconds) // “犹豫时间”,正态分布


    // 条件循环:模拟用户可能在结算前反复修改购物车

    .asLongAs(session => session("abandonCheckout").as[Boolean] == false) {

      exec(

        http("Checkout Preview")

          .get("/checkout/preview")

          .header("Authorization", "Bearer ${authToken}")

      )

      .pause(2 seconds)

      .randomSwitch(

        80.0 -> exec( // 80%的概率继续下单

          http("Confirm Order")

            .post("/order")

            .header("Authorization", "Bearer ${authToken}")

            .check(status.is(201))

            .exec(session => session.set("abandonCheckout", true)) // 订单创建成功,退出循环

        ),

        20.0 -> exec( // 20%的概率放弃或修改

          randomSwitch(

            50.0 -> exec(http("Remove Item").delete("/cart/item/1")), // 50%*20%=10% 概率删除商品

            50.0 -> exec { session => session.set("abandonCheckout", true) } // 50%*20%=10% 概率直接放弃

          )

        )

      )

    }


    // D. 下单后随机浏览或退出

    .randomSwitch(

      30.0 -> exec( // 30%的用户继续浏览其他页面

        http("Browse Recommendations")

          .get("/recommendations")

          .header("Authorization", "Bearer ${authToken}")

          .pause(Random.nextInt(10).seconds)

      ),

      70.0 -> exec( // 70%的用户直接退出

        pause(5 seconds) // 退出前的停留

      )

    )


  // --- 3. 设置负载模型 ---

  setUp(

    scn.inject(

      rampUsersPerSec(1).to(10).during(2 minutes), // 2分钟内逐渐增加到每秒10个用户

      constantUsersPerSec(10).during(5 minutes) // 然后保持10用户/秒不断5分钟

    )

  ).protocols(httpProtocol)

}


建议和规避

Session状态管理:

陷阱:在 repeat、during 内部使用 .feed(feeder.random) 可能导致每次迭代使用不同的Feeder数据,破坏情形连续性。

正确做法:如果需要在循环内使用同一用户的不同数据(就像一个用户查多个商品),应在循环外部 .feed 一次,在循环内部使用 ${变量} 引用;如果需要在循环内使用全新数据(如每次搜索新重点词),则需在循环内 .feed。


循环和时间的准确控制:

during和forever:during 保证总执行时间不超过指定时长,而 forever 会无限循环,一般需要配合 exitHereIfFailed 或全局时间限制。

负载精确:在 during 块内,Gatling只控制第一个虚拟用户进入和最后一个虚拟用户退出的时间差,不保证每个用户在整个期间不断活动。更精确的不断负载需靠 inject 注入方法控制。


随机性和可重复性:

调试:在脚本开发阶段,使用 Random.setSeed(123L) 固定随机数种子,使每次运行结果可复现。

生产压测:移除种子,保证真正的随机性。


Gatling通过 Random 模拟微观不确定性,通过 Feeder 提供宏观数据多样性,再通过循环和条件思路将这些元素编织成动态、真实的用户会话流。

文章标签: 软件测试 测试工具
热门标签 换一换
CNAS软件测评报告 CMA软件测评报告 首版次软件认定 软件结题验收 软件测试报告书 软件质量检测 数据库测试 H5应用测试 软件质检机构 第三方质检机构 第三方权威质检机构 信创测评机构 信息技术应用创新测评机构 信创测试 软件信创测试 软件系统第三方测试 软件系统测试 软件测试标准 工业软件测试 软件应用性能测试 应用性能测试 可用性测试 软件可用性测试 软件可靠性测试 可靠性测试 系统应用测试 软件系统应用测试 软件应用测试 软件负载测试 API自动化测试 软件结题测试 软件结题测试报告 软件登记测试 软件登记测试报告 软件测试中心 第三方软件测试中心 应用测试 第三方应用测试 软件测试需求 软件检测报告定制 软件测试外包公司 第三方软件检测报告厂家 CMA资质 软件产品登记测试 软件产品登记 软件登记 CNAS资质 cma检测范围 cma检测报告 软件评审 软件项目评审 软件项目测试报告书 软件项目验收 软件质量测试报告书 软件项目验收测试 软件验收测试 软件测试机构 软件检验 软件检验检测 WEB应用测试 API接口测试 接口性能测试 第三方系统测试 第三方网站系统测试 数据库系统检测 第三方数据库检测 第三方数据库系统检测 第三方软件评估 课题认证 第三方课题认证 小程序测试 app测试 区块链业务逻辑 智能合约代码安全 区块链 区块链智能合约 软件数据库测试 第三方数据库测试 第三方软件数据库测试 软件第三方测试 软件第三方测试方案 软件测试报告内容 网站测试报告 网站测试总结报告 信息系统测试报告 信息系统评估报告 信息系统测评 语言模型安全 语言模型测试 软件报告书 软件测评报告书 第三方软件测评报告 检测报告厂家 软件检测报告厂家 第三方网站检测 第三方网站测评 第三方网站测试 检测报告 软件检测流程 软件检测报告 第三方软件检测 第三方软件检测机构 第三方检测机构 软件产品确认测试 软件功能性测试 功能性测试 软件崩溃 稳定性测试 API测试 API安全测试 网站测试测评 敏感数据泄露测试 敏感数据泄露 敏感数据泄露测试防护 课题软件交付 科研经费申请 软件网站系统竞赛 竞赛CMA资质补办通道 中学生软件网站系统CMA资质 大学生软件网站系统CMA资质 科研软件课题cma检测报告 科研软件课题cma检测 国家级科研软件CMA检测 科研软件课题 国家级科研软件 web测评 网站测试 网站测评 第三方软件验收公司 第三方软件验收 软件测试选题 软件测试课题是什么 软件测试课题研究报告 软件科研项目测评报告 软件科研项目测评内容 软件科研项目测评 长沙第三方软件测评中心 长沙第三方软件测评公司 长沙第三方软件测评机构 软件科研结项强制清单 软件课题验收 软件申报课题 数据脱敏 数据脱敏传输规范 远程测试实操指南 远程测试 易用性专业测试 软件易用性 政府企业软件采购验收 OA系统CMA软件测评 ERP系统CMA软件测评 CMA检测报告的法律价值 代码原创性 软件著作登记 软件著作权登记 教育APP备案 教育APP 信息化软件项目测评 信息化软件项目 校园软件项目验收标准 智慧软件项目 智慧校园软件项目 CSRF漏洞自动化测试 漏洞自动化测试 CSRF漏洞 反序列化漏洞测试 反序列化漏洞原理 反序列化漏洞 命令执行 命令注入 漏洞检测 文件上传漏洞 身份验证 出具CMA测试报告 cma资质认证 软件验收流程 软件招标文件 软件开发招标 卓码软件测评 WEB安全测试 漏洞挖掘 身份验证漏洞 测评网站并发压力 测评门户网站 Web软件测评 XSS跨站脚本 XSS跨站 C/S软件测评 B/S软件测评 渗透测试 网站安全 网络安全 WEB安全 并发压力测试 常见系统验收单 CRM系统验收 ERP系统验收 OA系统验收 软件项目招投 软件项目 软件投标 软件招标 软件验收 App兼容性测试 CNAS软件检测 CNAS软件检测资质 软件检测 软件检测排名 软件检测机构排名 Web安全测试 Web安全 Web兼容性测试 兼容性测试 web测试 黑盒测试 白盒测试 负载测试 软件易用性测试 软件测试用例 软件性能测试 科技项目验收测试 首版次软件 软件鉴定测试 软件渗透测试 软件安全测试 第三方软件测试报告 软件第三方测试报告 第三方软件测评机构 湖南软件测评公司 软件测评中心 软件第三方测试机构 软件安全测试报告 第三方软件测试公司 第三方软件测试机构 CMA软件测试 CNAS软件测试 第三方软件测试 移动app测试 软件确认测试 软件测评 第三方软件测评 软件测试公司 软件测试报告 跨浏览器测试 软件更新 行业资讯 软件测评机构 大数据测试 测试环境 网站优化 功能测试 APP测试 软件兼容测试 安全测评 第三方测试 测试工具 软件测试 验收测试 系统测试 测试外包 压力测试 测试平台 bug管理 性能测试 测试报告 测试框架 CNAS认可 CMA认证 自动化测试
专业测试,找专业团队,请联系我们!
咨询软件测试 400-607-0568