LoadRunner脚本开发全流程:从协议选择到参数化关联实战
2026/7/5 5:46:49 网站建设 项目流程

1. 项目概述:从录制到回放,构建可信的虚拟用户

性能测试的核心,是模拟真实用户对系统施加压力,从而评估其在高负载下的表现。而模拟的逼真度,直接决定了测试结果的可信度。LoadRunner作为一款经典的性能测试工具,其脚本开发环节——主要由Virtual User Generator(简称VuGen)完成——正是构建这些“虚拟用户”灵魂的关键。很多团队在性能测试中踩坑,根源往往不在于场景设计或结果分析,而在于脚本本身:一个录制完未经任何处理的脚本,就像一台只会复读的机器,它无法处理动态数据,无法模拟思考时间,更无法应对复杂的业务逻辑,用它跑出来的结果,其参考价值微乎其微。

因此,掌握VuGen脚本开发的全流程,远不止是学会点“录制”和“回放”按钮。它是一套从业务理解、协议选择开始,贯穿脚本录制、增强、调试,直至最终参数化和关联的完整工程。这个过程的目标,是让每一个虚拟用户(Vuser)都能像一个有血有肉的真实用户那样去操作,携带独立的身份,处理动态的响应,并在操作间有合理的停顿。今天,我就结合自己多年在金融、电商等多个高并发项目中的实战经验,为你拆解这个全流程中的每一个关键步骤、背后的原理,以及那些手册上不会写的“坑”与技巧。

2. 脚本开发全流程核心思路拆解

2.1 流程全景与核心理念

在动手之前,我们必须建立一个正确的认知:VuGen脚本开发不是一个线性的“录制-运行”过程,而是一个迭代的、以“真实性”和“可重用性”为目标的工程循环。一个完整的脚本开发流程,通常包含以下几个核心阶段,它们环环相扣:

  1. 前期准备与协议分析:这是最容易被忽视却至关重要的第一步。你需要明确测试的业务流程,并准确判断应用所使用的网络协议。
  2. 脚本录制与初步捕获:利用VuGen的录制功能,捕获客户端与服务器之间的网络交互数据,生成初始脚本。
  3. 脚本清理与增强:删除冗余请求,插入事务(Transaction)和集合点(Rendezvous),并加入思考时间(Think Time),使脚本逻辑清晰且符合真实用户行为模型。
  4. 动态数据处理:这是脚本的“灵魂”所在。通过关联(Correlation)处理服务器返回的动态值(如Session ID、订单号),通过参数化(Parameterization)为不同的虚拟用户提供不同的输入数据(如用户名、搜索关键词)。
  5. 脚本调试与验证:确保脚本能够单用户、无错误地回放,其业务结果符合预期(如成功登录、成功下单)。
  6. 脚本强化与容错:添加逻辑判断、错误处理机制,使脚本在压力测试中更健壮。

这个流程的核心驱动力,是让脚本从“记录一次操作”变成“模拟一类用户行为”。例如,一个登录脚本,不应该只是回放你录制时输入的那个“张三”的账号密码,而应该能让1000个虚拟用户分别使用1000个不同的账号密码成功登录。这就是参数化和关联要解决的问题。

2.2 协议选择的底层逻辑与常见误区

协议选择是VuGen脚本开发的基石,选错了协议,后续所有工作都是徒劳。VuGen支持上百种协议,但日常高频使用的集中在Web(HTTP/HTML)、Web Services、Socket等几类。

为什么协议如此重要?因为VuGen本质上是一个“协议客户端模拟器”。它需要知道如何“说”应用程序使用的“语言”(协议),才能正确地构建请求包、解析响应包。选择“单协议”还是“多协议”,取决于你的应用架构。

  • Web(HTTP/HTML):这是最常用的协议,用于测试基于浏览器的B/S架构应用。它录制的是浏览器与Web服务器之间的HTTP请求和响应。这里有一个关键选择:HTML-based script还是URL-based script
    • HTML-based script:VuGen会尝试理解HTML页面结构,将页面内的资源(如图片、JS、CSS)请求自动关联到前一个页面请求中,脚本更贴近用户视角(一个动作对应一个函数,如web_submit_form),易于理解和增强。这是绝大多数Web应用的推荐选择,尤其适合现代动态Web应用。
    • URL-based script:录制所有独立的HTTP请求,包括每个资源的请求都会生成单独的web_url函数。脚本冗长,但控制粒度最细。通常只在HTML-based模式无法正确录制或需要精细控制每个请求时使用。
  • Web Services:用于测试SOAP或RESTful API。这是目前微服务架构下的测试重点。选择此协议,VuGen会直接录制对API端点的调用(如web_custom_request),并可以方便地处理XML或JSON格式的请求与响应。
  • Windows Sockets:用于测试纯TCP/UDP Socket通信的应用,如一些游戏服务器、自定义协议的中间件等。它录制的是底层的Socket数据流,脚本是二进制或文本格式的lrs_sendlrs_receive函数,需要开发者对协议格式有深入了解。

实操心得:协议选择避坑指南

  1. 不确定时,先用“单协议”:对于大多数Web应用,直接选择“单协议 -> Web (HTTP/HTML)”开始录制。如果VuGen自动探测不到,再尝试“多协议”并勾选可能的协议组合。
  2. 观察录制结果:录制后,如果脚本中充满了web_url请求图片、CSS等静态资源,而缺少核心的提交动作(如web_submit_form),很可能是因为应用采用了大量前端框架(如React, Vue.js)的异步加载,HTML-based模式解析失败。此时可以尝试切换到URL-based模式,或者使用VuGen的“录制选项”调整录制粒度。
  3. 对于手机APP测试:不要试图直接录制手机协议。标准做法是,在PC上设置代理(如Fiddler、Charles),将手机的网络代理指向PC,然后在VuGen中选择“Web (HTTP/HTML)”协议,并设置代理录制。这样就能捕获到APP发出的所有HTTP/HTTPS请求。对于非HTTP协议(如自定义TCP),则需要使用Socket协议并配合抓包工具分析报文格式。

3. 脚本录制、清理与结构化增强

3.1 录制配置与实战技巧

确定了协议,就可以开始录制。以最常用的Web (HTTP/HTML)协议为例,启动VuGen创建新脚本,选择协议后进入录制对话框。关键配置在“录制选项”(Recording Options)中:

  • 录制模式(Recording Mode):如前所述,优先选择HTML-based script
  • 浏览器(Browser):建议使用VuGen兼容列表内的浏览器,如IE或Chrome的特定版本。使用不兼容的浏览器可能导致录制失败或脚本异常。
  • URL地址(URL Address):填写你要测试的Web应用起始地址。
  • 工作目录(Working directory):脚本的存储位置。

点击“开始录制”,VuGen会打开指定的浏览器并开始捕获流量。此时,你就像正常用户一样操作业务流程即可,例如:打开首页 -> 登录 -> 搜索商品 -> 加入购物车 -> 下单 -> 退出。

录制完成后,VuGen会自动生成脚本,并显示在脚本视图中。同时,“录制快照”会显示录制过程中捕获的页面截图,这对于后续的脚本增强和调试非常有帮助。

注意事项:录制环境与数据准备录制前,务必准备一个干净的测试环境。避免在已登录状态的浏览器中开始录制,这会导致登录步骤缺失。最好使用无痕模式或全新浏览器会话。同时,想清楚你要录制的“典型业务场景”是什么,使用一套独立的测试数据(如test_user01),避免与线上或其他测试数据冲突。

3.2 脚本清理:去芜存菁,提升效率

刚录制的脚本通常包含大量“噪音”,主要是对静态资源(如图片、样式表、JavaScript文件)的请求。这些请求在性能测试中通常不是压力瓶颈(它们可以被浏览器缓存或CDN加速),但会显著增加脚本的复杂度、回放时间,并消耗不必要的压力机资源。

清理策略:

  1. 自动过滤:在“录制选项” -> “高级” -> “脚本”中,可以设置自动过滤掉某些资源类型(如.jpg, .png, .css, .js)。但需谨慎,有些.js文件可能包含重要的业务逻辑请求。
  2. 手动删除:回放脚本,在“回放日志”中观察哪些请求是必须的(通常返回200状态码且对业务有影响),哪些是可选的(如返回304 Not Modified的缓存请求或静态资源)。在脚本中注释或删除那些非必需的web_url调用。
  3. 一个简单的判断原则:如果删除某个请求后,单用户回放依然能成功完成业务流程,那么这个请求通常可以安全删除。重点关注那些提交数据的web_submit_formweb_custom_request以及关键的页面跳转请求。

3.3 插入事务与集合点:定义度量与制造并发

脚本清理后,我们需要为其注入结构,以便在Controller中能清晰地度量性能,并制造真实的并发压力。

  • 事务(Transaction):事务用来衡量一个或多个操作所消耗的时间。例如,“登录”事务应包含从点击登录按钮到成功跳转到首页的所有服务器请求。在VuGen中,使用lr_start_transaction(“登录”)lr_end_transaction(“登录”, LR_AUTO)将相关操作包裹起来。事务必须成对出现,且名称一致。在结果分析时,我们主要关注事务的响应时间、通过率等指标。

    • 实操技巧:事务的起点和终点要精准。起点通常放在触发业务操作的请求之前,终点放在该操作完成、页面稳定之后(例如,放在跳转后页面最后一个关键元素加载完成的请求之后)。避免将思考时间包含在事务内。
  • 集合点(Rendezvous):集合点用于在场景中让虚拟用户同步,模拟瞬间的并发操作。例如,模拟“秒杀”场景,需要在点击“立即抢购”按钮前设置一个集合点,让所有虚拟用户准备好后同时发出请求。使用lr_rendezvous(“秒杀提交”)插入集合点。

    • 重要警告:集合点必须与事务结合使用,且通常放在事务开始之后、关键请求之前。绝对不要将集合点放在lr_think_time()函数内或事务外,这会导致虚拟用户无意义地等待或同步混乱。在Controller中,你需要手动启用集合点策略才会生效。
  • 思考时间(Think Time):思考时间模拟真实用户在操作间隔的等待(如阅读页面内容、填写表单)。录制时,VuGen会默认记录操作间隔作为lr_think_time()。在压力测试时,我们可以在Controller中设置思考时间的处理方式:忽略、按录制时间回放、按比例随机化。为了产生持续的压力,在调试脚本时可以先忽略思考时间;但在真实负载场景中,建议使用按比例(如50%-150%)随机化,以更真实地模拟用户行为差异。

4. 脚本的灵魂:参数化与关联实战解析

如果说事务和集合点定义了脚本的骨架,那么参数化和关联就是赋予脚本灵魂和血液的关键。

4.1 参数化:让每个虚拟用户成为独立个体

参数化解决了“数据唯一性”和“数据驱动”的问题。你不能让1000个用户都用“张三”登录。

操作步骤:

  1. 在脚本中选中需要参数化的静态值(如用户名username)。
  2. 右键选择“替换为参数”(Replace with a Parameter)。
  3. 为参数命名(如P_UserName),并选择参数类型。最常用的是“文件”(File)类型。
  4. 在参数文件中(如P_UserName.dat),按列准备好测试数据。每一行代表一个虚拟用户可能使用的值。
  5. 在参数属性中,设置“选择下一行”(Select next row)和“更新值的时间”(Update value on)策略。
    • 选择下一行
      • Sequential(顺序):每个Vuser按顺序取数据。
      • Random(随机):每次随机取。
      • Unique(唯一):每个Vuser分配唯一值,确保不重复。这是最常用且重要的策略,特别是对于登录名、订单号等唯一性约束字段。
    • 更新值的时间
      • Each iteration(每次迭代):每次脚本迭代更新参数值。
      • Each occurrence(每次出现):每次遇到该参数都更新(很少用)。
      • Once(一次):整个场景运行中只取一次值。

一个电商登录下单的参数化示例:我们需要参数化:用户名、密码、搜索关键词、商品ID。

  • 创建P_UserP_PwdP_KeywordP_ProductID四个文件参数。
  • P_UserP_Pwd采用Unique+Each iteration策略,并且两列数据行行对应,确保账号密码匹配。
  • P_Keyword可以采用Random+Each iteration,模拟用户随机搜索。
  • P_ProductID可以采用Sequential+Each iteration,假设我们有一批固定的测试商品。

踩坑实录:参数化文件与数据准备

  1. 数据量不足:如果使用Unique策略,但参数文件中的数据行数少于虚拟用户数乘以迭代次数,VuGen会报错“参数P_XXX无更多唯一值”。务必确保数据充足。一个技巧是,在Controller中设置“当超出值时”(When out of values)为“中止虚拟用户”(Abort Vuser),而不是“循环”(Continue with last value),后者会导致数据重复,破坏测试真实性。
  2. 文件格式与路径:参数文件默认保存在脚本目录的dat文件夹下,是.dat格式的文本文件。如果数据中包含逗号,需要使用引号包裹,或者更改分隔符。在脚本迁移到其他机器时,注意参数文件的相对路径问题。
  3. 密码等敏感信息:避免在脚本中明文硬编码密码。即使参数化,文件也是明文存储。对于安全要求高的测试,可以考虑在运行时从加密存储或外部系统中动态获取,但这需要更高级的脚本开发能力。

4.2 关联:处理服务器返回的动态数据

关联是脚本开发中最具挑战性的一环。它的目的是捕获服务器响应中动态变化的值(如会话IDJSESSIONID、订单号orderId、CSRF令牌_token),并将其保存到一个参数中,供后续请求使用。

为什么需要关联?因为很多请求具有状态性。例如,登录后服务器会分配一个唯一的Session ID,后续所有操作都必须携带这个ID,服务器才知道是谁在操作。如果脚本直接使用录制时捕获的固定ID,第二个虚拟用户回放时就会因为Session失效而失败。

关联的核心方法:VuGen提供了自动关联和手动关联两种方式。

  1. 自动关联(扫描与规则)

    • 录制后自动扫描:录制完成后,点击菜单栏的“工具” -> “扫描关联规则”。VuGen会根据内置规则(如对JSESSIONIDVIEWSTATE等常见动态值的规则)扫描整个脚本和快照,提示可能的关联点。你可以选择接受或拒绝。
    • 回放时自动关联:在“运行时设置”(Run-time Settings) -> “互联网协议” -> “关联”中,启用“在回放期间检测到新动态参数时执行关联”。当回放脚本遇到与录制时不同的响应值时,VuGen会弹出对话框建议关联。这对于未知的动态值非常有用。
    • 局限性:自动关联并非万能,对于自定义格式的响应(如JSON中的“token”: “a1b2c3”)或者结构复杂的响应,它可能无法识别。
  2. 手动关联(必备技能):这是性能测试工程师必须掌握的核心技能。步骤是“找、存、用”。

    • 第一步:找(Find the value)。比较录制和回放的服务器响应,定位动态值。使用VuGen的“对比”工具(Tools -> Compare with Vuser)最方便。它会高亮显示两次运行中响应内容的不同之处,那个不同的字符串很可能就是需要关联的动态值。
    • 第二步:存(Save the value)。确定左右边界(LB/RB),使用web_reg_save_param_ex(或更早版本的web_reg_save_param)函数将其捕获到参数中。关键点:这个函数必须放在触发该响应的请求之前(它是一个“注册型”函数)。
    • 第三步:用(Use the parameter)。在后续需要该动态值的请求中,用参数(如{CorrToken})替换原来的硬编码值。

一个经典的登录Session关联示例:假设登录后,服务器在响应头中返回一个Set-Cookie: JSESSIONID=ASDF1234GHJK;

  1. 录制脚本:录制登录过程,脚本中后续请求的请求头里会包含Cookie: JSESSIONID=ASDF1234GHJK
  2. 回放失败:回放时,第一个虚拟用户用新的账号登录,服务器返回新的JSESSIONID=ZXCV5678TYUI,但脚本后续请求仍发送旧的ASDF1234GHJK,导致服务器返回401/403错误。
  3. 手动关联
    • 在登录请求(web_submit_form(“login”)之前,插入关联函数:
      web_reg_save_param_ex( “ParamName=Corr_JSESSIONID”, “LB=Set-Cookie: JSESSIONID=”, “RB=;”, “Search=Headers”, LAST);
    • 找到后续需要携带Cookie的请求(如查询请求),将其请求头中的JSESSIONID=ASDF1234GHJK替换为JSESSIONID={Corr_JSESSIONID}

高级技巧:处理JSON/XML响应的关联现代API大量使用JSON响应。对于形如{“token”: “abc123”, “userId”: 1001}的响应,我们可以使用边界更精确的web_reg_save_param_ex,或者使用LoadRunner的JSON/XPATH解析函数(如lr_json_string_to_objectlr_json_get_value,取决于VuGen版本)。这需要你熟悉JSON结构,并编写更灵活的提取逻辑。例如,先捕获整个JSON响应体,再从中解析出特定字段的值。

5. 脚本调试、验证与强化

5.1 回放调试与日志分析

脚本增强后,必须进行单用户回放调试,确保其逻辑正确。使用VuGen的“运行”(F5)或“验证”(Verify)功能。

关键检查点:

  1. 回放日志(Replay Log):这是最重要的调试信息源。务必将其级别设置为“扩展日志”(Extended Log)或至少“参数替换日志”(Parameter Substitution)。在日志中,你可以看到:
    • 每个请求的发送和接收情况。
    • 参数替换的实际值(显示Notify: Parameter Substitution)。
    • 关联函数捕获到的值(显示Notify: Saving Parameter)。
    • 事务的开始和结束时间。
    • 任何警告(Warning)或错误(Error)信息。
  2. 回放快照(Replay Snapshot):与录制快照对比,直观地查看关键步骤的页面是否一致。
  3. 输出窗口(Output Window):查看脚本编译和运行的概要信息。

常见回放错误及排查思路:

错误现象可能原因排查步骤
Action.c(x): Error -26612: HTTP Status-Code=500服务器内部错误。脚本逻辑可能正确,但服务器处理失败。1. 检查参数化数据是否合法(如超长用户名)。
2. 检查关联是否成功,动态值是否被正确替换。
3. 查看服务器日志获取更详细错误信息。
Action.c(x): Error -27979: Requested form not found在提交表单时,VuGen找不到对应的表单。1. 检查前一个请求的响应是否成功,页面是否正常加载。
2. 检查表单字段是否被正确关联或参数化。
3. 可能是动态表单名,需要关联name属性。
Action.c(x): Error -35061: No match found for the requested parameter关联失败,未找到匹配的动态值。1. 检查关联函数的左右边界(LB/RB)是否准确,是否包含了空格或换行。
2. 检查关联函数放置的位置是否正确(必须在产生该响应的请求之前)。
3. 使用“扩展日志”查看服务器返回的实际响应内容,重新确定边界。
事务失败(状态非PASS事务内的操作未完成。1. 检查事务的结束点lr_end_transaction是否被正确执行(例如,因为前面的错误导致脚本提前退出)。
2. 检查事务的响应时间是否超长,触发了超时设置。

5.2 添加逻辑控制与错误处理

一个健壮的脚本不应在遇到非致命错误时就崩溃退出。我们需要添加逻辑判断和错误处理。

  • 检查点(Text Check):用于验证页面内容是否符合预期,例如登录后页面是否包含“欢迎,XXX”字样。使用web_reg_findweb_find函数。web_reg_find是注册型函数,效率更高,推荐使用。如果检查点失败,可以配合lr_fail_transaction将事务标记为失败,但脚本可以继续执行。

    web_reg_find(“Fail=NotFound”, “Search=Body”, “Text=欢迎您”, LAST); // 接下来是提交登录的请求 web_submit_form(...); // 如果上一步的响应体中找不到“欢迎您”,则`web_reg_find`会触发失败,事务状态会受影响。
  • 条件判断与流程控制:使用C语言的if-elseswitchforwhile等语句。例如,根据检查点结果决定后续流程:

    if (strstr(lr_eval_string(“{ResponseBody}”), “库存不足”) != NULL) { lr_output_message(“商品已售罄,执行备选方案。”); // 跳转到其他商品或结束迭代 return 0; } else { // 继续下单流程 web_submit_form(“place_order”); }
  • 错误处理与继续运行:在“运行时设置”(Run-time Settings)中,可以配置错误处理。建议在调试阶段设置为“在错误时暂停”,以便定位问题。在正式压测时,可以设置为“在错误时继续”,并指定“快照失败迭代”,这样单个Vuser的失败不会影响整个场景,并且我们能获取失败时的上下文信息用于分析。

6. 集成与高级应用考量

当单个脚本调试通过后,工作并未结束。我们需要考虑脚本在真实负载场景中的表现以及更复杂的测试需求。

6.1 在Controller中集成与验证

将脚本放入Controller设计场景时,需要进行最终验证:

  1. 参数文件路径:确保Controller能访问到脚本的参数文件(.dat)。通常将脚本和dat文件夹一起打包上传到负载生成器是稳妥的做法。
  2. 运行时设置继承:Controller中的Vuser会继承VuGen脚本中的“运行时设置”,但可以在Controller层面进行覆盖(如统一设置超时时间、思考时间策略)。
  3. 运行一次Vuser:在场景设计界面,先使用“运行一次Vuser”功能,在目标负载生成器上执行单个脚本,确保环境依赖(如浏览器、网络、被测系统连通性)没有问题。

6.2 处理身份验证与加密通信

  • HTTPS/SSL证书:对于HTTPS网站,录制时VuGen会自动处理证书。如果遇到证书错误,需要在“运行时设置”->“互联网协议”->“首选项”中,启用“忽略证书错误”或导入正确的证书。在负载生成器上也需要确保有相应的根证书信任。
  • OAuth/Token认证:现代API常用OAuth 2.0等Token认证。脚本需要先调用一个认证接口(通常需要client_idclient_secret),从响应中获取access_token,然后将此Token以Bearer形式添加到后续所有API请求的Header中(Authorization: Bearer {AccessToken})。这本质上是一个关联操作。
  • 数字签名与加密参数:一些对安全性要求高的接口,参数可能被加密或需要数字签名。这无法通过简单的录制回放实现。你需要和开发人员确认加密/签名算法,然后在VuGen中使用C语言代码调用相应的加密库(如OpenSSL)或自己实现算法,动态生成参数值。这是脚本开发中的高级课题。

6.3 性能测试脚本的维护与版本管理

性能测试脚本不是一次性的。随着应用迭代,接口和前端可能发生变化,脚本也需要同步更新。

  1. 建立基线版本:为每个稳定的应用版本保存一份可用的脚本集。
  2. 版本控制:使用Git、SVN等工具对脚本进行版本管理,记录每次修改的原因(如:因登录接口变更更新关联规则)。
  3. 模块化与函数库:对于公共操作(如登录、退出),可以将其封装成自定义函数,放在vuser_init或单独的头文件(.h)中,供多个Action调用。这极大地提升了脚本的可维护性和复用性。
  4. 定期回归:在每次应用发布前,用旧的脚本进行快速回放验证,确保核心业务流程的脚本依然有效。

脚本开发是性能测试的基石,一个粗糙的脚本会导致整个测试活动失去意义。从精准的协议选择开始,通过细致的录制、彻底地清理、合理地结构化,再注入参数化和关联的灵魂,最后经过严格的调试和强化,你才能得到一个真正能够模拟真实用户、产生可信负载的优质脚本。这个过程需要耐心、细心和对业务的深入理解。记住,你的脚本不是为你一个人运行,它将在压力下代表成千上万的虚拟用户与系统对话,它的每一行代码都影响着这场对话的真实性与测试结论的有效性。多花时间在脚本开发上,是在为整个性能测试项目的成功打下最牢固的基础。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询