LoadRunner

LoadRunner

LoadRunner contains the following components

  • The Virtual User Generator or VuGen records end-user business processes and creates an automated performance tseting script,known as a Vuser script.虚拟用户生成器或VuGen记录最终用户的业务流程并创建一个自动性能测试脚本,称为Vuser脚本
  • The Controller organizes,driveres,manages,and monitors the load test.controller(控制器)组织、驱动、管理和监视负载测试
  • Analysis helps you view,dissect,and compare the results of the load tests.Analysis(分析器)可以帮助您查看、分析和比较负载测试的结果
  • Load Generators,computers that run Vusers to generate a load on the system.loadGenerators(负载生成器)运行vuser向服务器发起负载测试的计算机

在这里插入图片描述

特定

  1. 广分支持业界标准协议

  2. 支持多种平台开发脚本

  3. 创建真实的系统负载

    VuGen创建脚本时变量参数化,实现并发用户不同行为,然后再在controller中借助集合点实现真正意义上的并发测试

  4. 强大的实时监控与数据采集功能

    实时监控场景状态,掌握测试进度,及时发现问题

  5. 精确分析结果,辅助定位问题
    在这里插入图片描述

  6. 采用虚拟用户生成器进行脚本录制、脚本编写、脚本调试,完成脚本二的准备工作

  7. 铜鼓共脚本组合设计压测场景

  8. 调度压力机进行场景分布式压测

  9. 性能结果分析、图表分析

linux装压力机

不是全国职业院校职业大赛的考题范围,没学

脚本录制

能够将可视化操作转换为脚本代码,并且能够进行重复性的操作

简化操作,大大降低工作量和难度

  1. 直接录制

  2. 本地代理录制

  3. 离线流量录制

  4. 手动代理录制

  5. 第三方代理

    fiddler进行辅助生成脚本

录制方式
直接录制

在这里插入图片描述在这里插入图片描述

本地代理录制

Recording Options-Advanced

打开Use the LoadRunner Proxy to record a local application

在这里插入图片描述

离线流量录制

浏览器F12 以HAR格式保存所有内容

在这里插入图片描述
在这里插入图片描述

远程代理录制

在这里插入图片描述

第三方录制

同离线流量,只不过改成用fiddler录制了

录制优化

脚本结构认识

Actions:脚本区

Extra Files:头文件区

Runtime Setting:运行时设置

Parametes:参数设计

Recording Report:录制报告

Replay Summary:回放总结

录制优化
  1. 基于html和基于url脚本的区别

    html录制的脚本比较简单(资源型请求放在开头,压测去掉就行)

    url将各种请求拆开了

  2. http头过滤,内容类型过滤,资源/非资源类型的定义

回放优化

log:日志(Extended log-Data returned by server)更详细的日志

think time:思考时间

lr_think_time(10);
//启动回放时间时,在回放时在代码处会暂停10s

preferences-General

在这里插入图片描述

小结

View-Layouts-Reset to defaults 恢复默认布局

  1. 录制前设置好编码,以防中文乱码

    • Recording Options—HTTP Properties—Advanced
    • Runtime Settings—Preference—General
  2. 脚本录制

    脚本录制有多种方法,看个人喜好,倾向于本地代理流线流量录制。录制过程中要对脚本进行基本的过来和处理,提出一些无用静态请求和业务上认为无关的请求,让脚本最终处于最简洁的状态,降低后续的难度

  3. 结构优化

    正对录制好的脚本,我们要进行结构整理,设计好初始脚本,迭代脚本,退出脚本三个最基本的环节,针对复杂的脚本,我们要将迭代部分进行逻辑分拆,让其尽可能简化

  4. 脚本回放

    录制好的脚本要记得进行回放,并学会回放日志分析业务,进一步确认我们的脚本逻辑

脚本编写

脚本参数化

在各种业务场景中,我将多个常量用统一变量进行替代的过程称之为脚本参数化

  1. 脚本参数化加强了代码的可读性,非常方便看出关联
  2. 脚本参数化降低了测试代码的维护难度,非常方便我们快速修改,减少低级错的发生
  3. 比如主机,端口,查询条件,以及其它的业务数据的可根据需要进行参数化
内置参数

在LoadRunner中,内置了多种不同类型的参数,合理的采用会降低脚本的难度和提升脚本设计效率

  1. LoadGN

    全称为LoadGeneratorName,该参数是以压力机名称为基础,可按不同格式生成

    //定义一个LoadGeneratorName参数
    char* NewParam=lr_eval_string("{NewParam}");//把参数转换为字符串并赋值给NewParam变量
    lr_log_message("参数1,LoadGeneratorName:%s",NewParam);
    

    [在这里插入图片描述

  2. UserID

    该参数是以虚拟用户的序号为基础,可按不同格式生成

    //定义一个Vuser ID参数
    lr_log_message("参数,Vuser ID:%s",lr_eval_string("{NewParm}"));
    

在这里插入图片描述

  1. table参数

    以白哦个中的行数据为基础生成的参数,支持记事本编辑以及从csv等文案金中导入,每一行各列之间的数据可以设置分隔符

    表格取数的6种组合规则

    1. 顺序:按照参数化的顺序一个一个的来取(Sequential)
    2. 随机:参数化中的数据,每次随机的从中选取数据(Random)
    3. 唯一:为每个虚拟用户分配一个唯一的一条数据(Unique)

    更新值的规则

    • 每一次迭代时更新(Each iteration)
    • 运行场景中只更新一次(once)
    情况组合
    顺序-迭代更新a1-a2-a3-a1-a2
    顺序-仅更新一次a1-a1-a1-a1-a1
    随机-迭代更新每次都随机选择
    随机-仅跟新一次仅随机选一次(值相同)
    唯一-迭代更新首行
    唯一-仅跟新一次随机选择一次
    //定义一个表参数
    lr_Log_message("参数3,表参数:%s",lr_eval_string("NewParam"));
    

    [在这里插入图片描述

  2. file参数

    文件与表格的区别在于

    表格可以取整行数据,文件一般只取一行中的一列

    file参数可以有多列,每次取一列

    取下一行数据方法有三种

    1. 顺序:按照参数化的顺序一个一个的来取
    2. 随机:参数化中的数据,每次随机的从中选取数据
    3. 唯一:为每个虚拟用户分配一个唯一的一条数据

    更新值得规则

    1. 每一次迭代时更新
    2. 每一次出现时跟新
    3. 运行场景中更新一次
    //定义一个file参数
    lr_log_message("参数6,file参数:%s",lr_eval_string("{param6}"));
    
  3. 迭代编号

    该参数是以运行逻辑得替代次数为基础,可按不同格式生成

    //定义一个迭代编号参数
    char* NewParam=lr_eval_string("{NewParam}");
    

    在这里插入图片描述

    %07d就是编号前面补些0直至凑齐7位数字

  4. 日期时间

    能按照时间生成不同格式字符串

    更新值得规则

    1. 每一次迭代时更新
    2. 每一次出现时更新
    3. 运行场景中更新一次
    //定义一个日期时间参数
    lr_log_message("%s",lr_eval_string("{NewParam}"));
    

    在这里插入图片描述

  5. 随机数字

  6. 唯一编号

    能在范围内随机生成唯一数字

    更新值得规则

    1. 每一次迭代时更新
    2. 每一次出现时更新
    3. 运行场景中更新一次
    //定义一个唯一编号参数
    lr_log_message("%s",lr_eval_string("{NewParam}"));
    

    在这里插入图片描述在这里插入图片描述

  7. xml参数

    以xml结构为基础的参数

    取下一行数据方法有三种

    1. 顺序:按照参数化的顺序一个一个的来取
    2. 随机:参数化中的数据,每次随机的从中选取数据
    3. 唯一:为每个虚拟用户分配一个唯一的一条数据

    更新值得规则:

    • 每一次迭代时更新
    • 每一次出现时更新
    • 运行场景中更新一次
    //定义一个xml参数
    lr_log_message("%s",lr_eval_string("{param}"))
    

    在这里插入图片描述

  8. 自定义参数

规则关联

一般在业务系统中,我们再发起请求时,有可能用到前面步骤的返回结果:lr关联时指把服务器返回数据(部分数据)以参数来表示,同时为后续请求的一个变量这样一个过程,规则关联分为手动关联和自动关联

手动关联
  1. 找到前置请求中返回的业务数据
  2. 将上述数据设置为参数
  3. 将后续条件采用参数化替代
//从服务端返回中取认证数据
web_reg_save_param("devToken","LB=\"devt_token\":\","RB=\"",LAST);
lr_log_message("取得结果为:%s",lr_eval_string("{devToken}"));
//将认证数据放置头部信息中
web_add_auto_header("Authorization","Bearer{devToken}");

参数名称devToken

左边界:”devToken”:“

有边界:“

没找到时:报错(ERROR)

在body里找

在这里插入图片描述

web_reg_save_param("devToken",
    "LB=\"devToken\":\"",
    "RB=\"",
    "NotFound=ERROR",
    "Search=Body",
LAST);
//请求函数
自动关联

由loadrunner内置规则在录制时会自动生成关联,比如JSESSION,COOKIE自动关联

另外所有的自动关联均可以用手动关联替代,因此手动关联我们的学习重点

事务定义

事务(Transaction)用于模拟用户的一个相对完整的有意义的业务操作过程,例如人登录、查询、转账,这些都可以作为事务,而一般不会把每次HTTP请求作为一个事务

//事务开始
lr_start_transaction("devt-query");
//事务结束
lr_end_transaction("devt-query",LR_AUTO);
//事务成功结束
lr_end_transaction("devt-query",LR_PASS);
//事务失败结束
lr_end_transaction("devt-query",LR_FAIL);


//实例
//不检查结果,自动结束
lr_end_transaction("devt-query",LR_AUTO);
//判断是否成功
if(atoi(lr_eval_string("{paraml}"))>0){
    lr_end_transaction("devt-query",LR_PASS);
}else{
    lr_end_transaction("devt-query",LR_FAIL);
}
web_reg_save_param("rspCode",
    "LB=\"rspCode\":",
    "RB=,",
    "Search=Body",
    LAST
);
web_reg_save_param("treeName","LB=\"treeName\":\"","RB=\"","Search=Body",LAST);
//此处省去请求
//请求的response带有"rspCode":1,"rspDesc":"success"
if(atoi(lr_eval_string("{rspCode}"))>0){
    //atoi(),字符串转整数
    lr_end_transaction("longge_query",LR_PASS);
}else{
    lr_end_transaction("longge_query",LR_FAIL);
}
if(strcmp(lr_eval_string("{treeName}"),"{treeName}")==0){
    //strcmp(),比较参数的值,一样的话{treeName}就不为空
    lr_end_transaction("longge-query",LR_FAIL);
}else{
    lr_end_transaction("longger-query",LR_PASS);
}
结果检查

利用结果检查函数,我们可以判断业务是否正确,类似于断言

//找一个字段welcome
web_reg_find("Text=Welcome",
            LAST);
web_reg_find("Fail=NotFound",
             "Search=Body",
             "SaveCount=Token_Count",
             "TextPfx=\"devt_token\":\"",
             "TextSfx=\"",
            LAST);

在这里插入图片描述

小结
  1. 脚本参数化,规则关联,事务,结果检查时脚本二编写的几个核心场景
  2. 文件类、日期类、唯一编号、自定义参数在脚本参数化中使用非常多,比如
    • 在订单场景入库的时候,我们可以采用唯一编号,生成一些数据序列
    • 主机,端口等,我们可以采用自定义参数管理
  3. 通常我们的脚本在录完之后,第一次有可能报错,这是由于一些关联没有做好,我们可以打开日志
    • 找到请求中返回的业务数据
    • 然后再利用脚本参数化进行处理
  4. 对于初学者,我们一定要多谢,多练,针对一些常用函数一定要熟悉

常用函数

注册函数和检查函数需要放于动作函数前面

调用结果需要在动作类后面

参数类函数
lr_eval_string
//将参数转化为字符串
lr_save_int(0,"searchCount");
lr_save_string("字符","str1");
if(atoi(lr_eavl_string("{searchCount}"))==0){
    lr_output_message("Is zero,%s",lr_eval_string("{searchCount}"));
}
lr_save_int(47,"searchCount");
if(atoi(lr_eval_string("{searchCount}"))!=0){
    lr_output_message("Not zero,%s",lr_eval_string("{searchCount}"));
}
lr_eval_json
//将字符串或文件转换为Json对象
char* json_input="{""\"firstName\":\"John\",""\"lastName\":\"smith\"""}";
lr_save_string(json_input,"JSON_Input_Param");
//创建json对象
lr_eval_json("Buffer={JSON_Input_Param}","JsonObjecct=json_obj_1",LAST);
//修改json对象值
lr_json_set_values("JsonObject=json_obj_1","Value=test1111","QueryString=$.firestName","SelectAll=Yes",LAST);
//取得json对象值
lr_json_get_values("JsonObject=json_obj_1","ValueParam=test1_result","QueryString=$.firstName",LAST);
//json传字符串
lr_json_stringify("JsonObject=json_obj_1","Format=compact","OutputPatam=Rsult",LAST);
//打印结果
lr_log_message("%s--%s",lr_eval_string("{test1_result}"),lr_eval_string("{Result}"));
return 0;
lr_json_set_values
//修改Json对象中的值
lr_json_get_values
//获取对象中的值
lr_json_stringify
//Json对象转字符串
lr_save_string
//将变量以字符串类型存入参数
char strl[100] = "我是测试字符串";
lr_save_string(strl,"Paraml");
lr_log_message("%s",lr_eval_string("{Paraml}"));
lr_save_int
//将变量以数字类型存入参数
int n=1314;
lr_save_int(n,"paraml");
lr_log_message("%s",lr_eval_string("{paraml}"));
lr_save_datetime
//时间格式化,精确到秒,存入参数
lr_save_datetime("%Y-%m-%d %H:%M:%S",TIME_NOW,"currDateTime");
lr_output_message(lr_eval_string("{currDateTime}"));
lr_save_timestamp
//将时间戳存入到参数,可精确到秒,毫秒,微秒

//以秒为单位
lr_save_timestamp("param","DIGITS=10",LAST);
lr_output_message(lr_eval_string("{param}"));
//以毫秒为单位
lr_save_timestamp("param",LAST);
lr_output_message(lr_eval_string("{param}"));
//以微秒为单位
lr_save_timestamp("param","DIGITS=16",LAST);
lr_output_message(lr_eval_string("{param}"));
web_save_timesamp
//将时间戳存入到参数,固定为毫秒
web_save_timestatmp_param("tStamp",LAST);//默认以毫秒为单位,将时间戳存入参数
lr_output_message(lr_eval_string("Timestamp:{tStamp}"));
lr_param_sprintf
//格式化字符串,类似于sprintf
int index = 56;
char * suffix = "txt";
//底层采用C的sprintf函数
lr_param_sprintf("LOG_NAME_PARAM","log_%d.%s",index,suffix,100);
lr_output_messsage("The new file name is %s",lr_eval_string("{LOG_NAME_PARAM}"));
lr_convert_string_encoding
//编码转换,可防止中文乱码
lr_convert_string_encoding("中文",LR_ENC_SYSTEM_LOCALE,LR_ENC_UTF8,"RelyMessage");
lr_log_message("%s","{ReplyMessage}");
检查类函数
web_reg_find
//搜索指定字符串
web_reg_find("Search=Body","Text=devt_token",LAST);
//搜索指定字符串(开始+结束)
web_reg_find("Search=Body","TextPfx\"devt_token\":\"","TextSfx=\"");
//统配搜索
web_reg_find("Text/ALNUMLC=\"devt_token\"",LAST);
web_reg_save_param
//将动态数据注册到参数

//从服务端返回中取得数据,支持双右边界
web_reg_save_param("devtToken","LB=\"devt_token\":\"","RB=\"",LAST);
web_reg_save_param_regexp
//将动态数据注册到参数,比web_reg_save_param功能强大

//从服务端返回中取得数据
web_reg_save_param_regexp("ParamName=devtToken","RegExp=(\"RegExp=(\"devt_token\":\".*?\")","Group=0",SEARCH_FILTERS,"Scope=BODY",LAST);
web_reg_save_param_json
//以json方式解析动态1数据并注册到参数(要求数据为json)

//从服务端返回中取得数据
web_reg_save_param_json("ParamName=devtToken","QueryString=$..devt_token","SEARCH_FILTERS","Scope=BODY",LAST);
web_reg_save_param_xpath
web_reg_save_param_xpath(
    "ParamName=CorrelationParameter",
    "QueryString=/LR_EXTENSION[1]/object[1]/object[1]/array[1]","DFEs=JsonXml","ReturnXML=Yes",SEARCH_FILTERS,"SCope=Body",LAST
);

web_reg_save_param_attib

//以html文档方式解析数据并注册到参数

//<INPUT TYPE="HIDDEN" NAME="fieldl" VAULE="测试数据">
web_reg_save_param_attrib("ParamName=paraml","TagName=input","Extract=value","Name=fieldl","Type=*",SEARCH_FILTERS,"IgnoreRedirection=No",LAST);
//把input标签中name=fieldl的value值赋给paraml
日志类函数
lr_output_message
//向日志文件、输出窗口和其他测试报告摘要发送消息
lr_output_message("取得token为:%s",lr_eval_string("{devtToken}"));
lr_log_message
//向日志文件发送消息
lr_output_message("取得token为:%s",lr_eval_string("{devtToken}"));
lr_debug_message
//向日志文件发送调试消息(需要设置日志级别)
lr_debug_message(LR_MSG_CLASS_RESULT_DATA|LR_MSG_CLASS_PARAMETERS,lr_eval_string("1111{devtToken}"));
lr_error_message
//向日志文件发送错误消息
lr_error_message("取得token为:%s",lr_eval_string("{devtToken}"));
常用C函数
sprintf
//格式化字符串
//类似于lr_param_sprintf

char* param1="I am param1!";
char* param2="I am Param2!";
int num1=123;
char dest[100];
sprintf(dest,"%s %s %d",param1,param2,num1);
lr_log_message(dest);
strcat
//连接两个字符串
char fullpath[1024];
char * filename = "logfile.txt";
strcat(fullpath,"c:\\tmp");
strcat(fullpath,"\\");
strcat(fullpath,"filename");
lr_output_message("当前文件路径为%s",fullpath);
strchr
//查找第一次出现的字符
char* string = "His Excellency the Duke of Exeter";
char* first_x,* last_x;
first_x = (char *)strchr(string,'x');
lr_output_message("第一次出现的字符x:%s",first_x);
last_x = (char *)strrchr(string,'x');
lr_output_message("最后一次出现的字符x:%s",last_x);
strcmp
//比较两字符串的字母顺序,可用于判断是否相等
int result;
char tmp[20];
char string1[] = "The quick brown dog jumps over the lazy fox";
char string2[] = "The quick brown dog jumps over the lazy fox";
result = strcmp(string1,string2);
if(result > 0)
    strcpy(tmp,"greater than");
else if(result < 0)
    strcpy(tmp,"less than");
else
    strcpy(tmp,"equal to");
lr_output_message("strcmp:String 1 is %s string2",tmp);
strcpy
//将一个字符串复制到另一个字符串
char fullpath[1024],* filename = "logfile.txt";
strcpy(fullpath,"c:\\tmp");
lr_output_message("fullpath after strcpy:%s",fullpath);
stricmp
//忽略大小写,比较两字符串的字母顺序,可用于判断是否相等

int result;
char tmp[20];
char string1[] = "The quick brown dog jumps over the lazy fox";
char string2[] = "The QUICK brown dog jumps over the lazy fox";
result = stricmp(string1,string2);
if(result > 0)
    strcpy(tmp,"greater than");
else if(result < 0)
    strcpy(tmp,"less than");
else
    strcpy(tmp,"equal to");
lr_output_message("strcmp:String 1 is %s string2",tmp);
strlen
//返回字符串的长度
int is_digit,i=0;
char * str = "213431241";
unsigned int len = strlen(str);
do{
    if(i == len){
        lr_output_message("No letters found in string");
        return -1;
    }
    if_digit = isdigit(str[i++]);
}
while(is_digit);
lr_output_message("The first letter appears in character %d of string",i);
strncat
//把src所指向的字符串追加到dest所指向的字符串的结尾,直到n字符长度为止

char src[50], dest[50];
strcpy(src, "This is source");
strcpy(src, "This is destination");
strncat(dest,src,5);
lr_log_message("最终的目标字符串:%s",dest);
strnicmp
//对n个字符串执行不区分大小写的比较

int result;
char tmp[20];
char string1[] = "The quick brown dog jumps over the lazy fox";
char string2[] = "The QUICK brown dog jumps over the lazy fox";
result = strnicmp(string1,string2);
if(result > 0)
    strcpy(tmp,"greater than");
else if(result < 0)
    strcpy(tmp,"less than");
else
    strcpy(tmp,"equal to");
lr_output_message("strcmp:String 1 is %s string2",tmp);
行动类函数
//一般录制所得,能看懂就行

lr语言编程

变量使用

LoadRunner中的变量其实就是C语言的变量,不过有以下约束

  1. 变量可以定义在.h文件中
  2. 变量可以定义在Action函数外部
  3. 变量可以定义在Action开始部分
  4. Action体内不可用定义变量
int a1 = 0;
int a2 = 0;
char* p1;
char str2[] = "string1123412";
Action()
{
    lr_log_message("%s",&str2[5]);
    p1 = lr_eval_string("{param1}");
    lr_log_message("%s",p1);
    //int a3=0;//此处编译会报错
    return 0;
}
参数操作

参数是一个loadrunner中的概念

参数可以认为是C语言中的一个全局变量,我们书写脚本过程中,要学会用参数化的思想取解决问题

  1. 字符串数类的操作

    char str1[] = "str11";
    //参数的取值
    lr_log_message("%s",lr_eval_string("{param1}"));
    lr_log_message("%s",lr_eval_string("{param2}"));
    //参数的赋值
    lr_save_string(str1,"param1");
    lr_save_string(str2,"param2");
    //参数的取值
    lr_log_message("%s",lr_eval_string("{param1}"));
    lr_log_message("%s",lr_eval_string("{param2}"));
    
  2. int类型的操作

    //参数的取值
    lr_log_message("%s",lr_eval_string("{param1}"));
    lr
    

场景压测

LoadRunner中常见(Scenario)是一种用来模拟大量用户操作的技术手段,通过配置和执行场景向服务器产生负载,验证系统中各项性能指标是否达到用户要求:场景通过一系列的脚本组合,并通过1到多个压力机来产负载

  1. 了解一下Controller界面,大体熟悉一下各项菜单
  2. 场景分两种,一种是计划场景,一种是目标场景
  3. 场景先进行设计,然后再运行,运行时可查看各项性能指标,运行完成后可分析性能结果
基本操作
计划场景的设计演示

User Generator中Tools-Create Controller Scenario…

在这里插入图片描述

结果分析

  1. TPS越高,响应时间越小,性能越好,反之性能越差
  2. 同一场景中,可以采用前后对比测试,用来去欸但那个前后性能的好坏(一般伴随着程序有优化处理)
  3. 同一场景中,可以采用横对比,来确定不同事务中性能好坏
报告输出

Controller中Results-Analyze Results

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值