简介:这份资源是面向高校软件测试课程学习者与性能测试入门者的实验资料包,对应软件测试质量保证课程中LoadRunner性能测试工具实验二,重点解决并发批量注册用户与并发订票操作两类场景的脚本增强、参数化配置与结果分析问题。包内共356个文件,以log运行日志、dat数据文件、txt说明、def定义文件、html报告、xml配置及c、h源码等为主,另有少量cfg、ini、mdb等配置与数据库文件,压缩包约2.19MB,目录结构保留了脚本、参数文件与结果报告的原始组织方式。资源围绕集合点、事务、文本检查点等函数添加,以及虚拟用户数、迭代次数、资源监控与Analyze Results分析流程展开,并附有50并发20次迭代、10用户订票、阶梯加压至50并发等练习题参考。已有692人学习,适合需要对照实验步骤、复盘脚本配置与排错思路的读者参考。
1. 软件测试质量保证:LoadRunner 性能测试工具实验二到底在测什么
很多人第一次接触 LoadRunner 性能测试工具实验二,会以为它只是实验一录制脚本的重复劳动。实际上,实验一解决的是“能不能跑通”,实验二解决的是“跑得够不够真、够不够狠、数据能不能信”。我带过几届新人做性能测试,十个人里有八个卡在实验二,脚本能回放,报告也能生成,但一问并发用户数怎么来的、事务响应时间为什么忽高忽低,就答不上来。这篇笔记就围绕 LoadRunner 性能测试工具实验二这个场景,把参数化、关联、集合点、场景设计和结果分析这条链路拆开讲。适合已经跑通过一次录制回放、准备把性能测试做扎实的测试工程师,也适合要交实验报告但不想只交截图的学生。读完你至少能独立设计一个可信的并发场景,并知道报告里哪些数字不能直接拿去汇报。
2. 实验二的核心增量:从单用户回放到多用户真实并发
实验一和实验二最大的区别,不是工具换了按钮,而是测试目标变了。实验一只需要证明脚本能跑,实验二要证明系统在压力下的表现。这个转变带来三个必须处理的问题:数据不能重复、会话不能串、压力要能同步。下面先把这三个问题的原理讲清楚,再落到具体操作。
2.1 参数化:为什么同一份数据跑十次就失效
录制脚本时,登录用的账号密码是写死的。回放一次没问题,回放十次、一百次,要么被系统当成重复请求拦截,要么所有虚拟用户共用一条数据,测出来的根本不是并发。参数化的本质是把脚本里的常量替换成变量,让每个虚拟用户取到不同的值。
常见做法是准备一个数据文件,比如user.dat,每行一组账号密码,用逗号或制表符分隔。在 VuGen 里选中要替换的字符串,右键选择替换为参数,新建一个参数,类型选文件,指向这个数据文件。关键在“选择下一行”的策略,默认是顺序取,十个用户取十行,第十一个用户会从头开始。如果数据文件只有十行而你要跑五十个并发,就必须改成“唯一”或者“每次迭代取新值”,否则后四十个用户拿到的还是前十个账号。
user.dat 示例内容: testuser001,Pass@001 testuser002,Pass@002 testuser003,Pass@003参数化之后还要注意一件事:数据文件里的账号必须在被测系统里真实存在,且没有被锁定。我见过有人用生产环境的账号做参数化,跑完一轮把真实用户锁了一片,这就是血泪经验。实验环境里最好提前用接口批量注册一批专用测试账号,账号名带固定前缀,方便跑完清理。
2.2 关联:动态值不处理,脚本第二次就翻车
关联是实验二最容易翻车的地方。录制的时候,服务器返回一个动态的会话标识,脚本把它当成固定值写死了。第一次回放服务器认,第二次服务器生成新的标识,脚本还在用旧的,直接报错。这个动态值可能是登录后的 token、表单里的隐藏字段、或者某个校验码。
处理关联的步骤分三步。第一步,在录制日志或回放日志里找到报错位置,确认是哪个请求的参数对不上。第二步,在服务器返回的响应里定位这个动态值的来源,通常在一个隐藏域或者 JSON 字段里。第三步,在 VuGen 里用关联函数把这个值提取出来,存成变量,再替换到后续请求里。
// 从登录响应中提取动态 token web_reg_save_param("AuthToken", "LB=name=\"token\" value=\"", "RB=\"", "Search=Body", LAST); // 后续请求引用提取到的变量 web_custom_request("submit_order", "URL=http://test-server/order/submit", "Method=POST", "Body=token={AuthToken}&item=1001", LAST);web_reg_save_param必须写在产生该动态值的请求之前,这是注册函数,不是执行函数。LB和RB是左右边界,用来在响应文本里定位目标值。Search=Body表示在响应正文里找,如果动态值在响应头里,要改成Search=Headers。提取出来的变量用花括号引用,比如{AuthToken}。如果边界找错了,提取结果为空,后续请求就会带着空 token 发出去,报错信息往往指向后续请求,容易误导排查方向。
2.3 集合点:并发不是同时点按钮那么简单
很多人以为设置一百个虚拟用户就是一百个并发,其实 LoadRunner 默认是逐步启动的,每个用户跑自己的迭代,彼此之间没有同步。要制造真正的瞬时压力,必须用集合点。集合点的作用是让虚拟用户跑到某个位置时停下来等,等够指定数量再一起放行。
在脚本里插入集合点函数,通常放在事务开始之前。然后在 Controller 的场景设置里配置集合点的策略,比如“当百分之多少的用户到达集合点时释放”。如果策略设成百分之百,而某个用户因为前置步骤失败永远到不了集合点,整个场景就会卡死。所以实际做的时候,我一般设成百分之八十到九十,留一点容错空间。
// 在事务开始前插入集合点 lr_rendezvous("login_rendezvous"); lr_start_transaction("login"); web_submit_data("login_action", "Action=http://test-server/login", "Method=POST", "EncType=application/x-www-form-urlencoded", "Name=username", "Value={username}", ENDITEM, "Name=password", "Value={password}", ENDITEM, LAST); lr_end_transaction("login", LR_AUTO);集合点名字要和 Controller 里配置的一致,大小写敏感。事务的起止位置也要卡准,集合点放在事务外面,否则等待时间会被算进事务响应时间,数据就失真了。这一点在实验报告里经常被忽略,导致响应时间虚高。
3. 场景设计与执行:把并发模型落到 Controller 里
脚本调通只是第一步,实验二的重头戏在 Controller 里设计场景。场景设计决定了你测出来的数据有没有参考价值。下面从场景类型选择、负载曲线设计、监控指标配置三个方面讲。
3.1 手动场景还是面向目标场景:先想清楚要回答什么问题
Controller 提供两种场景类型。手动场景是你指定虚拟用户数和运行时长,适合回答“系统在两百并发下能撑多久”。面向目标场景是你指定一个目标,比如事务响应时间不超过两秒,让工具自动调整用户数,适合回答“系统最多能承受多少用户”。
实验二通常要求做手动场景,因为要观察不同并发梯度下的表现。我一般会设计三到四个梯度,比如五十、一百、两百、三百用户,每个梯度跑十分钟,中间留五分钟冷却。这样能画出趋势曲线,看出系统在哪个点开始劣化。如果只跑一个并发数,报告里只有一个点,说明不了容量拐点在哪里。
场景设计里还有一个容易忽略的参数:启动方式。同时启动所有用户会造成瞬间冲击,逐步启动更接近真实流量。我一般用每十五秒启动五个用户的方式,让压力平滑上升,观察系统在不同负载阶段的反应。
3.2 负载曲线与思考时间:别把压测跑成 DDoS
思考时间是虚拟用户两次操作之间的等待时间。录制脚本时,VuGen 会记录你真实操作时的间隔,回放时默认按录制值等待。如果直接忽略思考时间,每个用户会以极限速度发请求,测出来的吞吐量虚高,响应时间也失真。
在场景设置里,思考时间有三种处理方式:按录制值、按比例缩放、忽略。做容量测试时,我一般按录制值的百分之五十到七十来缩放,模拟用户操作快一点但还没到疯狂点击的程度。做稳定性测试时,按录制值原样保留,跑几个小时看系统会不会内存泄漏。
Runtime Settings 中思考时间配置项: - Replay thinking time: As recorded / Multiply recorded thinking time by / Ignore - 建议容量测试:Multiply by 0.5 ~ 0.7 - 建议稳定性测试:As recorded如果完全忽略思考时间,一百个用户可能产生上千 QPS,被测系统如果没做限流,直接被打挂。这不是系统性能不行,是压测方式不对。实验报告里要写清楚思考时间的处理策略,否则数据没法复现。
3.3 监控指标:光看 LoadRunner 的报告不够
LoadRunner 自己会收集事务响应时间、吞吐量、虚拟用户数这些指标,但系统层面的瓶颈它看不到。CPU 飙到百分之百、内存泄漏、数据库连接池耗尽,这些信息要靠外部监控。常见做法是在被测服务器上开性能计数器,Windows 用 PerfMon,Linux 用 nmon 或 sar,把数据导出来和 LoadRunner 的报告对齐时间轴。
我一般会重点看四个指标:事务平均响应时间、每秒事务数、服务器 CPU 使用率、数据库慢查询数量。如果响应时间上升的同时 CPU 没上去,瓶颈可能在 IO 或者锁等待。如果 CPU 上去了但吞吐量没涨,说明系统已经到处理极限。这些交叉分析才是实验二真正要练的能力。
4. 避坑与排查:实验二里最容易翻车的五个地方
性能测试的坑大多不在工具本身,而在环境、数据和理解偏差上。下面五条是我踩过或者见别人踩过的,按现象、原因、解决三段写。
4.1 回放成功但场景里大量报错
现象:在 VuGen 里单用户回放全部通过,放到 Controller 里跑多用户,错误率超过百分之三十。
原因:最常见的是参数化数据不够或者重复。单用户回放时只用第一行数据,当然没问题。多用户并发时,如果数据文件只有几行,后面的用户取到重复账号,被系统拒绝。另一个原因是关联没做全,单用户时某些动态值恰好没变,多用户时变了。
解决:先检查参数化文件的“选择下一行”策略,改成唯一取值,并确认数据行数大于最大并发用户数。再检查回放日志里有没有动态值警告,把所有变化的字段都做关联。最后在 Controller 里先跑五个用户验证,没问题再往上加。
4.2 事务响应时间忽高忽低,标准差比平均值还大
现象:报告里平均响应时间两秒,但最大值二十秒,标准差三秒,数据没法用。
原因:通常是集合点策略设成了百分之百,部分用户卡在集合点等待,等待时间被算进了事务。或者是思考时间没设,用户以极限速度发请求,系统排队严重。还有一种可能是被测系统本身有定时任务在跑,和压测时间重叠了。
解决:把集合点释放策略改成百分之八十到九十,并把集合点放在事务外面。设置合理的思考时间,不要忽略。确认压测期间没有其他定时任务或备份任务在跑。如果还不行,把压测时间拉长,看响应时间是不是周期性波动,是的话就是系统内部有定时操作。
4.3 吞吐量上不去,但服务器资源很闲
现象:并发用户加到两百,每秒事务数卡在一个值不动了,服务器 CPU 和内存都很低。
原因:瓶颈可能在 LoadRunner 压测机本身。一台普通笔记本跑两百个虚拟用户,CPU 和网络可能先到瓶颈。也可能是脚本里有同步等待,比如某个请求串行执行,限制了整体速度。还有可能是网络带宽不够,请求发不出去。
解决:先看压测机的资源使用率,如果压测机 CPU 满了,换一台性能更好的机器,或者用多台压测机分布式加压。检查脚本里有没有不必要的lr_think_time或者同步点。用ping和traceroute确认网络延迟正常。如果都没问题,再回头查被测系统的中间件配置,比如线程池大小、连接数限制。
4.4 关联函数提取为空,但边界看起来没错
现象:web_reg_save_param返回的变量是空字符串,后续请求带着空值发出去,报参数错误。
原因:边界字符串里有特殊字符没转义,比如引号、反斜杠。或者响应内容被压缩了,LoadRunner 默认不解压,导致在压缩后的乱码里找边界,当然找不到。还有一种情况是动态值在响应头里,但Search参数写的是Body。
解决:在 VuGen 的 Generation Log 里看原始响应内容,确认边界字符串和实际内容完全一致,包括空格和引号。如果响应是 gzip 压缩的,在 Runtime Settings 里开启“自动解压响应”。确认动态值的位置,头里就用Search=Headers,正文里就用Search=Body。实在找不到,用web_reg_save_param_regexp正则提取,容错性更好。
4.5 实验报告数据漂亮但无法复现
现象:报告里写了两百并发平均响应时间一点五秒,但别人照着同样的脚本和场景跑,结果差很远。
原因:没有记录环境信息。被测系统的版本、数据库数据量、中间件配置、压测机配置、网络环境,这些都会影响结果。只写并发数和响应时间,等于没写。
解决:报告里必须包含环境清单。被测系统版本和部署方式、数据库类型和数据量级、压测机 CPU 和内存、网络带宽、思考时间策略、集合点策略、参数化数据量。这些信息写清楚,别人才有可能复现。我一般会做一个环境配置表,跑之前填好,跑完直接贴进报告。
5. 从实验到实战:让性能测试数据真正能用来做决策
实验二做完,你手里会有一份报告,里面有响应时间、吞吐量、错误率。但这份报告能不能拿去支撑一个上线决策,取决于你有没有做下面三件事。
第一件事,建立基线。性能测试不是跑一次就完,要在系统稳定版本上跑一次基线,记录各项指标。以后每次迭代或者上线前再跑,和基线对比。如果响应时间涨了百分之二十以上,就要查原因。没有基线的性能测试,数据再漂亮也只是孤立的数字。我一般会把基线数据存成表格,每次压测后更新,形成趋势。
第二件事,做瓶颈定位而不是只报结果。报告里写“两百并发下响应时间三秒”,这只是现象。要往下挖一层:是应用服务器 CPU 满了,还是数据库慢查询多了,还是网络延迟大了。用前面说的交叉分析方法,把 LoadRunner 的数据和系统监控数据对齐,找到根因。这样开发团队才知道往哪个方向优化。
第三件事,区分容量测试和稳定性测试。容量测试是逐步加压找拐点,稳定性测试是在百分之七十到八十的负载下跑几个小时甚至过夜。两种测试的脚本配置、思考时间策略、监控重点都不一样。实验二通常只做容量测试,但实际项目里稳定性测试更能暴露内存泄漏和连接池耗尽这类问题。我一般会在容量测试找到拐点后,用拐点百分之七十的负载跑一个四小时的稳定性测试,观察内存和句柄数是否持续增长。
下面是一个简单的稳定性测试场景配置参考,用表格说明关键参数。
| 配置项 | 容量测试 | 稳定性测试 |
|---|---|---|
| 虚拟用户数 | 梯度递增至拐点 | 拐点的百分之七十 |
| 运行时长 | 每梯度十分钟 | 四小时以上 |
| 思考时间 | 录制值的百分之五十 | 录制值原样 |
| 集合点 | 启用,百分之八十释放 | 可选,或不启用 |
| 监控重点 | 响应时间、吞吐量拐点 | 内存、句柄、连接池趋势 |
最后说一个我自己的习惯。每次跑完 LoadRunner 场景,我不会马上关掉 Controller,而是先把原始结果文件另存一份,命名带上日期、版本、并发数。然后在报告里只放分析后的图表,原始数据留档。因为过两周有人问你“当时那个两百并发的数据还在吗”,你翻出原始文件比重新跑一遍省事得多。性能测试这行,后悔药就是留档。希望帮到你。
本文还有配套的精品资源,点击获取