LoadRunner脚本开发全流程:从协议选择到参数化关联实战

LoadRunner脚本开发全流程:从协议选择到参数化关联实战 1. 项目概述从录制到回放构建可信的虚拟用户性能测试的核心是模拟真实用户对系统施加压力从而评估其在高负载下的表现。而模拟的逼真度直接决定了测试结果的可信度。LoadRunner作为一款经典的性能测试工具其脚本开发环节——主要由Virtual User Generator简称VuGen完成——正是构建这些“虚拟用户”灵魂的关键。很多团队在性能测试中踩坑根源往往不在于场景设计或结果分析而在于脚本本身一个录制完未经任何处理的脚本就像一台只会复读的机器它无法处理动态数据无法模拟思考时间更无法应对复杂的业务逻辑用它跑出来的结果其参考价值微乎其微。因此掌握VuGen脚本开发的全流程远不止是学会点“录制”和“回放”按钮。它是一套从业务理解、协议选择开始贯穿脚本录制、增强、调试直至最终参数化和关联的完整工程。这个过程的目标是让每一个虚拟用户Vuser都能像一个有血有肉的真实用户那样去操作携带独立的身份处理动态的响应并在操作间有合理的停顿。今天我就结合自己多年在金融、电商等多个高并发项目中的实战经验为你拆解这个全流程中的每一个关键步骤、背后的原理以及那些手册上不会写的“坑”与技巧。2. 脚本开发全流程核心思路拆解2.1 流程全景与核心理念在动手之前我们必须建立一个正确的认知VuGen脚本开发不是一个线性的“录制-运行”过程而是一个迭代的、以“真实性”和“可重用性”为目标的工程循环。一个完整的脚本开发流程通常包含以下几个核心阶段它们环环相扣前期准备与协议分析这是最容易被忽视却至关重要的第一步。你需要明确测试的业务流程并准确判断应用所使用的网络协议。脚本录制与初步捕获利用VuGen的录制功能捕获客户端与服务器之间的网络交互数据生成初始脚本。脚本清理与增强删除冗余请求插入事务Transaction和集合点Rendezvous并加入思考时间Think Time使脚本逻辑清晰且符合真实用户行为模型。动态数据处理这是脚本的“灵魂”所在。通过关联Correlation处理服务器返回的动态值如Session ID、订单号通过参数化Parameterization为不同的虚拟用户提供不同的输入数据如用户名、搜索关键词。脚本调试与验证确保脚本能够单用户、无错误地回放其业务结果符合预期如成功登录、成功下单。脚本强化与容错添加逻辑判断、错误处理机制使脚本在压力测试中更健壮。这个流程的核心驱动力是让脚本从“记录一次操作”变成“模拟一类用户行为”。例如一个登录脚本不应该只是回放你录制时输入的那个“张三”的账号密码而应该能让1000个虚拟用户分别使用1000个不同的账号密码成功登录。这就是参数化和关联要解决的问题。2.2 协议选择的底层逻辑与常见误区协议选择是VuGen脚本开发的基石选错了协议后续所有工作都是徒劳。VuGen支持上百种协议但日常高频使用的集中在WebHTTP/HTML、Web Services、Socket等几类。为什么协议如此重要因为VuGen本质上是一个“协议客户端模拟器”。它需要知道如何“说”应用程序使用的“语言”协议才能正确地构建请求包、解析响应包。选择“单协议”还是“多协议”取决于你的应用架构。WebHTTP/HTML这是最常用的协议用于测试基于浏览器的B/S架构应用。它录制的是浏览器与Web服务器之间的HTTP请求和响应。这里有一个关键选择HTML-based script还是URL-based script。HTML-based scriptVuGen会尝试理解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_send和lrs_receive函数需要开发者对协议格式有深入了解。实操心得协议选择避坑指南不确定时先用“单协议”对于大多数Web应用直接选择“单协议 - Web (HTTP/HTML)”开始录制。如果VuGen自动探测不到再尝试“多协议”并勾选可能的协议组合。观察录制结果录制后如果脚本中充满了web_url请求图片、CSS等静态资源而缺少核心的提交动作如web_submit_form很可能是因为应用采用了大量前端框架如React, Vue.js的异步加载HTML-based模式解析失败。此时可以尝试切换到URL-based模式或者使用VuGen的“录制选项”调整录制粒度。对于手机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加速但会显著增加脚本的复杂度、回放时间并消耗不必要的压力机资源。清理策略自动过滤在“录制选项” - “高级” - “脚本”中可以设置自动过滤掉某些资源类型如.jpg, .png, .css, .js。但需谨慎有些.js文件可能包含重要的业务逻辑请求。手动删除回放脚本在“回放日志”中观察哪些请求是必须的通常返回200状态码且对业务有影响哪些是可选的如返回304 Not Modified的缓存请求或静态资源。在脚本中注释或删除那些非必需的web_url调用。一个简单的判断原则如果删除某个请求后单用户回放依然能成功完成业务流程那么这个请求通常可以安全删除。重点关注那些提交数据的web_submit_form、web_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个用户都用“张三”登录。操作步骤在脚本中选中需要参数化的静态值如用户名username。右键选择“替换为参数”Replace with a Parameter。为参数命名如P_UserName并选择参数类型。最常用的是“文件”File类型。在参数文件中如P_UserName.dat按列准备好测试数据。每一行代表一个虚拟用户可能使用的值。在参数属性中设置“选择下一行”Select next row和“更新值的时间”Update value on策略。选择下一行Sequential顺序每个Vuser按顺序取数据。Random随机每次随机取。Unique唯一每个Vuser分配唯一值确保不重复。这是最常用且重要的策略特别是对于登录名、订单号等唯一性约束字段。更新值的时间Each iteration每次迭代每次脚本迭代更新参数值。Each occurrence每次出现每次遇到该参数都更新很少用。Once一次整个场景运行中只取一次值。一个电商登录下单的参数化示例我们需要参数化用户名、密码、搜索关键词、商品ID。创建P_User、P_Pwd、P_Keyword、P_ProductID四个文件参数。P_User和P_Pwd采用UniqueEach iteration策略并且两列数据行行对应确保账号密码匹配。P_Keyword可以采用RandomEach iteration模拟用户随机搜索。P_ProductID可以采用SequentialEach iteration假设我们有一批固定的测试商品。踩坑实录参数化文件与数据准备数据量不足如果使用Unique策略但参数文件中的数据行数少于虚拟用户数乘以迭代次数VuGen会报错“参数P_XXX无更多唯一值”。务必确保数据充足。一个技巧是在Controller中设置“当超出值时”When out of values为“中止虚拟用户”Abort Vuser而不是“循环”Continue with last value后者会导致数据重复破坏测试真实性。文件格式与路径参数文件默认保存在脚本目录的dat文件夹下是.dat格式的文本文件。如果数据中包含逗号需要使用引号包裹或者更改分隔符。在脚本迁移到其他机器时注意参数文件的相对路径问题。密码等敏感信息避免在脚本中明文硬编码密码。即使参数化文件也是明文存储。对于安全要求高的测试可以考虑在运行时从加密存储或外部系统中动态获取但这需要更高级的脚本开发能力。4.2 关联处理服务器返回的动态数据关联是脚本开发中最具挑战性的一环。它的目的是捕获服务器响应中动态变化的值如会话IDJSESSIONID、订单号orderId、CSRF令牌_token并将其保存到一个参数中供后续请求使用。为什么需要关联因为很多请求具有状态性。例如登录后服务器会分配一个唯一的Session ID后续所有操作都必须携带这个ID服务器才知道是谁在操作。如果脚本直接使用录制时捕获的固定ID第二个虚拟用户回放时就会因为Session失效而失败。关联的核心方法VuGen提供了自动关联和手动关联两种方式。自动关联扫描与规则录制后自动扫描录制完成后点击菜单栏的“工具” - “扫描关联规则”。VuGen会根据内置规则如对JSESSIONID、VIEWSTATE等常见动态值的规则扫描整个脚本和快照提示可能的关联点。你可以选择接受或拒绝。回放时自动关联在“运行时设置”Run-time Settings - “互联网协议” - “关联”中启用“在回放期间检测到新动态参数时执行关联”。当回放脚本遇到与录制时不同的响应值时VuGen会弹出对话框建议关联。这对于未知的动态值非常有用。局限性自动关联并非万能对于自定义格式的响应如JSON中的“token”: “a1b2c3”或者结构复杂的响应它可能无法识别。手动关联必备技能这是性能测试工程师必须掌握的核心技能。步骤是“找、存、用”。第一步找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: JSESSIONIDASDF1234GHJK;。录制脚本录制登录过程脚本中后续请求的请求头里会包含Cookie: JSESSIONIDASDF1234GHJK。回放失败回放时第一个虚拟用户用新的账号登录服务器返回新的JSESSIONIDZXCV5678TYUI但脚本后续请求仍发送旧的ASDF1234GHJK导致服务器返回401/403错误。手动关联在登录请求web_submit_form(“login”)之前插入关联函数web_reg_save_param_ex( “ParamNameCorr_JSESSIONID”, “LBSet-Cookie: JSESSIONID”, “RB;”, “SearchHeaders”, LAST);找到后续需要携带Cookie的请求如查询请求将其请求头中的JSESSIONIDASDF1234GHJK替换为JSESSIONID{Corr_JSESSIONID}。高级技巧处理JSON/XML响应的关联现代API大量使用JSON响应。对于形如{“token”: “abc123”, “userId”: 1001}的响应我们可以使用边界更精确的web_reg_save_param_ex或者使用LoadRunner的JSON/XPATH解析函数如lr_json_string_to_object和lr_json_get_value取决于VuGen版本。这需要你熟悉JSON结构并编写更灵活的提取逻辑。例如先捕获整个JSON响应体再从中解析出特定字段的值。5. 脚本调试、验证与强化5.1 回放调试与日志分析脚本增强后必须进行单用户回放调试确保其逻辑正确。使用VuGen的“运行”F5或“验证”Verify功能。关键检查点回放日志Replay Log这是最重要的调试信息源。务必将其级别设置为“扩展日志”Extended Log或至少“参数替换日志”Parameter Substitution。在日志中你可以看到每个请求的发送和接收情况。参数替换的实际值显示Notify: Parameter Substitution。关联函数捕获到的值显示Notify: Saving Parameter。事务的开始和结束时间。任何警告Warning或错误Error信息。回放快照Replay Snapshot与录制快照对比直观地查看关键步骤的页面是否一致。输出窗口Output Window查看脚本编译和运行的概要信息。常见回放错误及排查思路错误现象可能原因排查步骤Action.c(x): Error -26612: HTTP Status-Code500服务器内部错误。脚本逻辑可能正确但服务器处理失败。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_find或web_find函数。web_reg_find是注册型函数效率更高推荐使用。如果检查点失败可以配合lr_fail_transaction将事务标记为失败但脚本可以继续执行。web_reg_find(“FailNotFound”, “SearchBody”, “Text欢迎您”, LAST); // 接下来是提交登录的请求 web_submit_form(...); // 如果上一步的响应体中找不到“欢迎您”则web_reg_find会触发失败事务状态会受影响。条件判断与流程控制使用C语言的if-else、switch、for、while等语句。例如根据检查点结果决定后续流程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设计场景时需要进行最终验证参数文件路径确保Controller能访问到脚本的参数文件.dat。通常将脚本和dat文件夹一起打包上传到负载生成器是稳妥的做法。运行时设置继承Controller中的Vuser会继承VuGen脚本中的“运行时设置”但可以在Controller层面进行覆盖如统一设置超时时间、思考时间策略。运行一次Vuser在场景设计界面先使用“运行一次Vuser”功能在目标负载生成器上执行单个脚本确保环境依赖如浏览器、网络、被测系统连通性没有问题。6.2 处理身份验证与加密通信HTTPS/SSL证书对于HTTPS网站录制时VuGen会自动处理证书。如果遇到证书错误需要在“运行时设置”-“互联网协议”-“首选项”中启用“忽略证书错误”或导入正确的证书。在负载生成器上也需要确保有相应的根证书信任。OAuth/Token认证现代API常用OAuth 2.0等Token认证。脚本需要先调用一个认证接口通常需要client_id和client_secret从响应中获取access_token然后将此Token以Bearer形式添加到后续所有API请求的Header中Authorization: Bearer {AccessToken}。这本质上是一个关联操作。数字签名与加密参数一些对安全性要求高的接口参数可能被加密或需要数字签名。这无法通过简单的录制回放实现。你需要和开发人员确认加密/签名算法然后在VuGen中使用C语言代码调用相应的加密库如OpenSSL或自己实现算法动态生成参数值。这是脚本开发中的高级课题。6.3 性能测试脚本的维护与版本管理性能测试脚本不是一次性的。随着应用迭代接口和前端可能发生变化脚本也需要同步更新。建立基线版本为每个稳定的应用版本保存一份可用的脚本集。版本控制使用Git、SVN等工具对脚本进行版本管理记录每次修改的原因如因登录接口变更更新关联规则。模块化与函数库对于公共操作如登录、退出可以将其封装成自定义函数放在vuser_init或单独的头文件.h中供多个Action调用。这极大地提升了脚本的可维护性和复用性。定期回归在每次应用发布前用旧的脚本进行快速回放验证确保核心业务流程的脚本依然有效。脚本开发是性能测试的基石一个粗糙的脚本会导致整个测试活动失去意义。从精准的协议选择开始通过细致的录制、彻底地清理、合理地结构化再注入参数化和关联的灵魂最后经过严格的调试和强化你才能得到一个真正能够模拟真实用户、产生可信负载的优质脚本。这个过程需要耐心、细心和对业务的深入理解。记住你的脚本不是为你一个人运行它将在压力下代表成千上万的虚拟用户与系统对话它的每一行代码都影响着这场对话的真实性与测试结论的有效性。多花时间在脚本开发上是在为整个性能测试项目的成功打下最牢固的基础。