说明:该篇博客是博主一字一码编写的,实属不易,请尊重原创,谢谢大家!
接着上一篇博客继续往下写 :https://blog.csdn.net/qq_41782425/article/details/103985087
关于LoadRunner性能测试,早在之前的《性能测试实战(一)》系列博客中有详细介绍使用
一、录制脚本前的准备工作
1.性能测试的原理
- 性能测试可以抓取客户机和服务器之间的通信数据,从而录取脚本。
2.明确软件架构
- B/S
- C/S
3.确定能使用的浏览器
- 最好用 IE,其他浏览器可能会丢失 http 请求。
4.选择正确的协议
- 协议分类表
- 选择协议的常用方法:
✔ 通过概要或详细设计手册获知所使用的协议。
✔ 询问开发工程师数据通讯采用何种协议。
✔ 根据以往测试经验来判断被测试对象采用的协议,这种方法具有猜测性,有时候不一定准确。
✔ 使用协议分析工具进行分析。
二、录制脚本
1.协议分析器
使用协议分析器分析软件适合选择何种协议。
- loadrunner提供了测试网站webtours
- 点击如下快捷方式,则可以打开webtours主页
- 创建脚本
- 进入后,点击协议分析器,首先分析一下单机软件calc.exe也就是电脑中的计算器
- 点击确定后,会打开计算器,然后出现分析窗口,可以查看到抓取数据为0
- 操作计算器,进行各种计算,结果还是0,说明该软件并不能进行性能测试
- 当关闭计算器时,则显示抓取到数据
- 停止分析,弹出分析报告,检测出此软件适合的协议
- 点击协议,则弹出录制脚本窗口
- 录制过程中,操作计算器,还是没有录制进去
- 停止录制后,会弹出任务界面,不在此界面查看,点击脚本,在脚本中查看
- 点击action,查看脚本没有任何动作,说明此软件无法进行性能测试
- 现在来对webtours网站进行分析,很明显就已经获取很多数据了
- 停止录制,查看分析结果,一一排除那么试用于第三个协议,如果不放心可以一个个协议的去试试看
2.使用 VUGen 录制脚本
2.1 两种录制方式
-
HTML 录制
✔ 模拟客户操作,默认方式。 -
URL 录制
✔ 显示每个请求,更方便调试。
【例 1】录制注册账号的脚本。
第一种方式:HTML录制
- 创建脚本
- 弹出窗口点击确定,即可录制
- 录制webtours网站的登录
第二种方式:URL录制 - 新创建一个脚本
- 录制窗口点击选项,选择录制方式
- 录制完成如下,代码量比较多
2.2 脚本视图
2.2.1 脚本视图(Script View)
-
Vuser_init
✔ 存放应用程初始化的脚本,执行脚本时只运行一次。 -
Vuser_end
✔ 存放应用程序注销时的脚本,执行脚本时只运行一次。 -
Action
✔ 脚本的代码体,可多次重复运行。 -
globals.h
✔ 存放全局变量和函数的声明语句。
2.2.2 树视图(Tree View)
- HTML 视图
✔ 显示截图界面。
- HTTP 视图
✔ 请求
★ 客户机给服务器发送数据
✔ 响应
★ 服务器给客户机发送数据
2.2.3 日志视图(Log)
- Recording Log(录制日志)
✔ 录制脚本时,vugen 会拦截 Client 端与 Server 端之间的对话,并且统统记录下来。在 Recording Log 中,可以找到浏览器与服务器之间所有的对话,包含通信内容、日期、时间、浏览器的请求、服务器的响应内容等。
- Generation Log (生成日志)
✔ 记录了脚本录制的设置,网络事件到脚本函数的转化过程。
- Replay Log(回放日志)
✔ 脚本回放运行时的输出都记在这个 Log 里 - 切换到脚本视图,点击播放按钮或者F5进行回放脚本,即可产生回放日志
3.运行脚本
3.1 运行期间显示图形界面
- 工具—常规选项—显示—勾选“回放期间…”
✔ 不建议场景运行时开启此项。
3.2 部分脚本解释
web_url(“WebTours”, | 步骤名称,网页最后单词,可自定义 |
---|---|
“URL=http://127.0.0.1:1080/WebTours/”, | 请求页面地址 |
“TargetFrame=”, | 当前连接资源的 frame 名称 |
“Resource=0”, | url 是否为资源(如图片、文件等,0 表示不是),每次重放脚本都重新下载 |
“RecContentType=text/html”, | 内容类型 |
“Referer=”, | 表示当前页面或资源从哪个页面链接过来的 |
“Snapshot=t1.inf”, | 页面快照名称 |
“Mode=HTML”, | 录制模式,url 录制显示为 http |
LAST); | 结束符 |
web_submit_form(“login.pl”, | 提交表单数据给服务器,用于 html 录制 |
web_submit_data(“login.pl”, | 提交数据给服务器,用于 url 录制 |
“Action=http://localhost:1080/WebTours/login.pl”, | 对应于 form 中的 Action,数据发给指定的URL |
“Method=POST”, | POST 方式发送数据 |
ITEMDATA, | 发送数据的开始标记 |
“Name=username”,“Value=test”, | ENDITEM, 结束一个数据 |
“Name=password”, “Value=1”, | ENDITEM, 结束另一个数据 |
lr_think_time(5); | 思考时间为 5s |
web_link(“sign up now”, | 点击了链接,Text 表示链接文字,用于 html"Text=sign up now", 录制 |
web_concurrent_start(NULL); | 两行之间的内容是多个请求,这些请求一起 |
web_concurrent_end(NULL); | 发给服务器,用于 url 录制 |
3.3 webtours案例
3.3.1 通过运行查看器查看脚本运行结果
- 录制注册脚本
- 勾选脚本运行时查看器
- 回放脚本,可以像QTP那样边执行脚本,边查看页面,因为录制注册和回放都是同一账号,所以页面上出现用户名被占用,很正常
- 在回放日志中,也会显示成功,因为loadrunner只是查看命令能不能执行,命令能否执行成功,最终页面上提示什么这都无所谓,只要浏览器给服务器发送数据就是成功
- 保存脚本
3.3.2 未增强脚本时进行负载测试的隐患
- 对webtours注册脚本进行负载测试
- 添加被测脚本
- 设置10个用户一开始同时运行
- 持续时间选择完成前一直运行
- 点击开始运行场景
- 点击vuser查看运行监控
- 查看事务
- 点击分析结果
- 如查看平均事务响应时间,那么不能够说10个用户同时注册需要1.42秒,因为这10个用户使用目前脚本同时注册时并不知道是不是真的注册成功了,所以这个结论是有问题的
三、增强脚本
说明:博主之前是在windows server 2008中进行loadrunner的安装及使用,因为不知道为什么比较卡,所以博主又在windows server 2008 R2中进行实操loadrunner
1.检查点
1.1 性能测试为什么使用检查点
进行压力测试时,经常会有页面间数据传递的操作,页面有可能会发生传递混乱,或者客户端与服务端数据传输被中断或传输了错误的数据等情况。为了判断数据传递的正确性, Loadrunner 在脚本中插入检查点,在每次运行时检查服务器返回的页面是否正确。
1.2 添加检查点
- 文本检查点函数
✔ web_reg_find(“Fail=NotFound”,"Text= 查找内容 ","SaveCount= 找到次数参数 ", “Search=查找范围”,LAST)
★ 在缓存中查找,是注册型函数,必须写在查找内容请求之前。
★ 检查时可以区分大小写、查询二进制数据、用#代替数字、用^匹配数字和字母。
★ 一般在 Tree View 视图中插入检查点(可以选择检查点函数)。
【例】添加检查点,验证账号注册是否成功
- 首先切换到树视图,查看运行时的截图,选择注册提交成功后的截图
- 选中检查文本,右击添加检查点
- 检查点设置,保存计数即表示参数名
- 切换到脚本视图中,可以看到生成了一个检查点函数,跟之前博主讲的QTP检查点不同的是,这里的位置不能改变,并且是在注册函数之前
1.3 读取参数到字符串(变量)
- lr_eval_string(“字符串{参数名}”);
✔ 字符串随意,取出的内容是字符串格式的,evaluate;
✔ 结果是变量形式。
1.4 输出函数
-
lr_output_message(变量);
✔ 默认输出字符串;
✔ 可以在日志中显示行号。
✔ 例如
★ lr_output_message(lr_eval_string(“字符串{参数名}”)); -
lr_output_message("%格式字符",变量);
✔ 常用格式字符
★ %s
■ 字符串
★ %c
■ 字符
★ %d
■ 整数
★ %f
■ 浮点数
-
lr_message("%格式字符",变量);
✔ "%格式字符"可以省略;
✔ 在日志中不显示行号。
-
在脚本中输出匹配到的文本检查点数目
-
运行脚本,因为找不到设置的文本检查点,所以报错导致无法打印出匹配个数
-
删除检查点函数中的"Fail=NotFound",,再次运行脚本没有报错,打印出匹配个数为0,这里有一个bug这是当不出现保存,那么则会在日志中显示成功找到,但是实际是没有找到的,打印结果为0
-
在打印语句中,加上辨识语句
-
删除cdtaogang用户数据,再次运行脚本,结果找到一个
1.5 出错继续运行的函数
-
lr_continue_on_error(1);
✔ 脚本出错后继续运行。 -
在之前的检查点函数去掉了失败=找不到,现在添加该属性,然后在检查点函数后面添加出错继续运行的函数
-
运行脚本,查看结果,说明了一切
-
删除cdtaogang用户数据,然后再次运行脚本,没有任何问题
2.事务
2.1 事务的含义
-
事务是客户要实现的业务,是在脚本中定义的某段操作(Action,就是一段脚本语句)。
-
事务代表一个完整的业务,统计响应时间需要事务,确定业务是否成功。
2.2 添加事务
- lr_start_transaction(“事务名称”)
- lr_end_transaction(“事务名称”,事务状态)
✔ LR_AUTO
★ 事务的状态被自动设置,如果事务执行成功,状态设置为 PASS,如果执行失败,状态设置 FAIL,如果由于异常中断,状态被设置成 STOP。
✔ LR_PASS
★ 事务函数如果执行成功,代码返回的状态是 PASS。
✔ LR_FAIL
★ 事务函数如果执行失败,代码返回的状态是 FAIL。
✔ LR_STOP
★ 事务函数如果由于异常中断,代码返回状态是 STOP。
【例 1】注册账号,添加事务。
- 将脚本分为打开网站、点击注册链接、提交注册数据三个部分,并为这三个部分添加检查点
- 在打开网站脚本结束处添加结束事务
- 事务添加如下
- 运行脚本,除了提交注册数据事务显示失败,其他都是成功,因为注册的用户名已存在
- 删除cdtaogang已注册数据,再次运行脚本,提交注册数据事务显示状态为通过
3.事务+检查点
3.1 定义变量
- 数据类型 变量名;
✔ 常用数据类型有 int、double、char,不支持 String;
✔ 如果放在 Action 内部话,要放在最前面,而且要集中放置,不允许被复制语句和其它语句间断;
✔ 可以放到 vuer_init 和 globals.h 中。
3.2 字符串的存储
- char *字符指针=“字符串数据”;
- char 字符数组名[ ]=“字符串数据”;
- char 字符数组名[ 字符个数+1 ]=“字符串数据”;
- char *字符指针;
字符指针=“字符串数据”; - char 字符数组名[ 字符个数+1 ]; strcpy(字符数组名,“字符串数据”);
✔ 不允许:字符数组名=“字符串数据”;
3.3 参数转存到整型变量
- 变量=atoi(lr_eval_string(“字符串{参数名}”))
✔ 将参数取出后,转为整数(ascii to integer)
4.if 语句
if(条件表达式){
语句 1;
}
else{
语句 2;
}
- 如果不想出现如下回放日志中检查点没有获取的报错信息
- 解决方法为,在注册检查点中删除Fail=NotFound,然后通过匹配的检查点个数来判断事务结束的状态为Pass还是Fail
4.1 事务与检查点结合if语句增强脚本
- 首先切换到树视图,添加打开网站检查点
- 为点击注册链接添加检查点
- 紧接着为打开网站结束事务以及点击注册链接结束事务进行检查点匹配数判断
- 删除cdtaogang用户数据,然后运行脚本,查看结束事务状态均为PASS通过
4.2 使用变量控制事务状态
- 通过以上脚本,回放脚本后,查看日志需要一个个的去查看事务的状态,比较麻烦,可以通过定义变量字符串a和b,整数类型变量s,对变量进行判断来获得事务的通过情况以及不通过的事务
4.3 未使用参数化时进行负载测试
- 添加注册脚本到负载测试中,配置计划如下
- 删除cdtaogang用户数据,运行负载测试,查看失败的事务数一共有9个,查看失败的事务,很明显因为第一次注册cdtaogang的用户成功,往后跑脚本都是用这个cdtaogang的用户在注册,那么肯定是失败的,所以显示9个失败
- 打开分析负载测试结果,查看提交注册数据事务的平均事务响应时间,可以得知为0.2296秒,但是这个结果是不正确的,因为10个用户同时注册只有一个是成功的并且所有成功,要想获得正确的事务平均响应时间,那么就需要用到参数化来使用10个不用的用户名来进行注册
5.参数化
5.1 参数化的作用
- 脚本参数化体现了数据驱动的思想,即测试脚本和测试数据分离的思想。脚本体现测试流程,数据体现测试案例。
- 参数化可以减少脚本的大小和脚本数量。
- 参数化使业务更接近真实的客户业务。
5.2 参数化的场合
- 程序中具有日期时间数据。
- 实现唯一性约束:如注册业务。
- 实现数据约束:如银行业务的动态码每次都不同,需要参数化。
- 缓存数据约束
✔ 数据库查询是从硬盘中读取查询结果,再读到内存,内存再读到缓存,最后将缓存中的数据发送到处理器中处理。若每次使用一致的查询条件,数据库的查询结果将会一致,由于数据已经在缓存中,系统不再读取硬盘,从而得到的响应时间要快于真实情况,这种情况也要参数化。
5.3 参数化的种类
【例 1】新建一个脚本,插入参数。
- 新建参数
- 配置参数名,点击属性配置
- 为test表添加值,选择增加行,或者可以用记事本编辑,在记事本中添加也可以(需要回车换行)
- 点击关闭,然后确定后,如下所示
- 通过lr_eval_string方法取出test参数的值,再通过lr_output_message打开出来,之前博主存放了三个数据,但只迭代一次所以打印出第一个数据cdtaogang1
- 选中脚本中的test参数,右击查看参数属性则可以看到之前的设置的数据了
5.4 使用数据文件参数化
5.4.1 设置迭代次数
- 即运行逻辑(Run Logic)设置
✔ F4→Run Logic
5.4.2 开启日志
- 控制在场景运行时显示日志信息。
- F4→日志 Log→扩展日志 Extended Log→参数替换 Parameter Substitution
5.4.3 虚拟用户-迭代-出现的关系
- 一个虚拟用户可以有多次迭代(Each iteration)
- 一次迭代中的参数可以出现(Each occurrence)多次
5.4.4 Select next row 与 Update value on 设置
- 针对 Controller 设置,脚本调试时无法验证。
✔ Sequential+Each iteration
★ 每一个 Vuser 每次迭代顺序取参数值;
★ 若数据全部执行完毕,则返回第一行继续读取。
- 在工具中创建手工场景
- 配置全局计划
- 运行场景,查看vuser中的第一个用户日志,因为选择的是顺序取值每次迭代选择下一个数据,所以取值如下
✔ Sequential+Each occurrence
★ 每一个 Vuser 每次迭代中,参数每次出现时,顺序取参数值。 - 设置参数为每次出现顺序取值
- 回到场景中的设计版块,选择详细信息,刷新脚本
- 执行场景,查看虚拟用户vuser运行日志,从中看到取值跟之前的不一样的,在第一次迭代中第一个取值为cdtaogang1,第二个取值为cdtaogang2,第二次迭代时第一个取值为cdtaogang3,第二个取值为cdtaogang1,原因很简单,设置了每次只要出现值时则进行更新而不是每次迭代才更新值,这里需要自己多多理解
✔ Sequential+Once
★ 每一个 Vuser 一直取用同一个参数。
- 执行场景,查看虚拟用户日志只取一次值,所以每次都是cdtaogang1
✔ Random:随机取值。
- 随机取值跟Sequential相似,博主这里就只演示一下Sequential+Each iteration,也就是说每次迭代时都会对cdtaogang1、cdtaogang2、cdtaogang3三个值随机取,运行场景,结果如下每次都是随机取的
✔ Unique+Each iteration
★ 迭代次数应设置为 1;
★ 每一个虚拟用户运行一次脚本选择一个顺序值
■ 假设 3 个虚拟用户,迭代 3 次,则
● 第 1 个用户第一次迭代选择第 1 行,第二次迭代选择第 2 行,第三次迭代选择第 3 行
● 第 2 个用户第一次迭代选择第 4 行,第二次迭代选择第 5 行,第三次迭代选择第 6 行
● 第 3 个用户第一次迭代选择第 7 行,第二次迭代选择第 8 行,第三次迭代选择第 9 行
- 执行场景,查看第一个用户日志,取得是cdtaogang1、cdtaogang2、cdtaogang3
- 查看第二个用户的日志,取得是cdtaogang4、cdtaogang5、cdtaogang6
- 查看第三个虚拟用户日志,取的是cdtaogang7、cdtaogang8、cdtaogang9
✔ Unique+Each occurrence
★ 这个组合不允许。
✔ Unique+Once
★ 迭代次数应设置为 1;
★ 每一个虚拟用户运行一次脚本选择一个唯一值,如假设 3 个虚拟用户,迭代 3 次,则第 1 个用户每次迭代选择第 1 行,第 2 个用户每次迭代选择第 2 行,第 3 个用户每次迭代选择第 3 行。
- 执行场景,查看第一个虚拟用户的取值三次迭代都是取的cdtaogang1
- 第二个虚拟用户三次迭代为cdtaogang2
- 第三个虚拟用户取值为cdtaogang3,也就是说每个用户只会对参数数据取值一次
- 【例】使用 200 个并发用户对注册进行负载测试,要求每次注册的用户都不同
✔ 参数化时,先选择间隔符,然后添加新列
✔ 注意
★ 参数选择使用 Unique+Once。 - 在webtours注册脚本中,对用户名和密码配置参数化(目前先配置一个,后面使用excel进行处理)
- 密码这里选择用户名文件,不用再创建表了,最后添加列即可
- 对于再次输入的密码直接使用现有参数pwd即可
- 接下来在本机新建excel表,创建测试数据并复制到LR中
- 确定后,在loadrunner中只显示了100行
5.4.5 参数表可视行数设置
- Loadrunner 的参数值没有最大的限度;
- 修改
✔ lr 安 装 路 径 \config\vugen.ini 文 件 , 在 此 文 件 “ [ParamTable]” 将 MaxVisibleLines=100 的值修改成为你想显示的值,如果文件中没有
[ParamTable],可自行添加
- 修改完成后,重新查看则显示200行了
- 创建100个用户手工场景
- 配置计划,让100个虚拟用户同事跑起来,持续时间为完成前一直运行
- 执行场景,100个虚拟用户全部执行成功,600个事务也全部成功(一个虚拟用户成功完成注册那么就是6个事务,100个用户则是600个事务)
- 打开用户存储文件夹,可以看到100个用户注册数据
- 博主忘了勾选扩展日志,所以这里将注册的100个用户数据删除,重新运行
- 这里事务其实不应该全部成功,因为检查点内容为固定的cdtaogang,但是这里匹配计数还是为1,正常来说应该是Fail,对检查点的内容也就是用户名进行参数化
- 对检查点进行参数化(记得保存脚本)
- 删除已注册用户数据,重新运行场景,查看虚拟用户日志,这下才是对的