news 2026/4/3 3:50:30

第三方CMA/CNAS软件测试测评机构【Gatling的随机性和真实性模拟:使用Random、Feeder与循环实现真实用户行为】

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
第三方CMA/CNAS软件测试测评机构【Gatling的随机性和真实性模拟:使用Random、Feeder与循环实现真实用户行为】

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

Random注入不确定性

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

随机等待时间

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

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 可用于模拟某些等待事件。

随机选择

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

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,测试脚本内嵌数据,无需外部文件。

文章来源:卓码软件测评

精彩推荐:点击蓝字即可
软件负载测试API自动化测试软件测试第三方软件测试软件性能测试软件测试机构

用法和性能优化

// 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. 基础循环

// 1. 固定次数循环:重复执行5次搜索操作 repeat(5) { exec(http("Search").get("/search?q=test")) .pause(1) } // 2. 使用动态变量控制循环:每个用户的循环次数不同(从Session中取) repeat("${desiredLoopCount}") { // 从Feeder或前置操作中获取变量 exec(...) }

2. 高级循环和退出条件

// 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 // 如果轮询失败,则此虚拟用户退出 }

实战模拟用户行为

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

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提供宏观数据多样性,再通过循环和条件思路将这些元素编织成动态、真实的用户会话流。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/3/28 10:40:57

AI如何帮你理解CHOWN命令?自动生成权限管理代码

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容: 创建一个Python脚本,使用subprocess模块自动执行CHOWN命令来修改文件/目录的所有者和组。要求:1) 接受用户输入文件路径、新所有者和组;2) 验证…

作者头像 李华
网站建设 2026/3/27 11:16:25

时光宝盒:一键留存QQ空间完整记忆档案

时光宝盒:一键留存QQ空间完整记忆档案 【免费下载链接】GetQzonehistory 获取QQ空间发布的历史说说 项目地址: https://gitcode.com/GitHub_Trending/ge/GetQzonehistory 在数字化浪潮中,那些记录青春岁月的QQ空间动态正面临不可预见的风险。账号…

作者头像 李华
网站建设 2026/3/31 6:01:54

智能人脸打码部署案例:基于BlazeFace的高效隐私保护方案

智能人脸打码部署案例:基于BlazeFace的高效隐私保护方案 1. 引言:AI 人脸隐私卫士 - 智能自动打码 在数字化内容爆炸式增长的今天,图像和视频中的人脸信息已成为敏感数据泄露的主要源头之一。无论是社交媒体分享、企业宣传照,还…

作者头像 李华
网站建设 2026/3/28 15:53:17

企业网络管理:Technitium MAC地址修改器实战案例

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容: 创建一个企业级MAC地址管理工具,功能包括:1) 批量修改多台设备的MAC地址 2) MAC地址预设模板管理 3) 修改记录审计日志 4) 网络连通性自动测试功能 5) 支持…

作者头像 李华
网站建设 2026/3/25 1:18:06

KILO CODE:AI如何革新你的编程工作流

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容: 开发一个基于KILO CODE的AI辅助编程工具,能够根据用户输入的自然语言描述自动生成代码片段,支持多种编程语言如Python、JavaScript等。工具应具备智能补全、…

作者头像 李华
网站建设 2026/3/28 9:38:33

GLM-4.6V-Flash-WEB完整指南:从部署到API调用详解

GLM-4.6V-Flash-WEB完整指南:从部署到API调用详解 智谱最新开源,视觉大模型。 1. 引言 1.1 视觉大模型的演进与GLM-4.6V-Flash的定位 近年来,多模态大模型在图文理解、视觉问答(VQA)、图像描述生成等任务中展现出强大…

作者头像 李华