LR总结笔记

性能:消耗的时间和资源的利用率
性能高:时间少、资源利用低
容量:相同空间,容量大,为有利
接口测试越来越重要,各种模块之间进行智能调用
httpwatch测试前端性能
virtualUser虚拟用户
单交易基准测试:按规定测试
单交易负载测试:需求出发,所能承受的最大负载 100个 200个 1个小时
单交易压力测试:需求出发,极限情况下系统会崩溃,是否具有自我恢复性100个 多少个小时会有问题
综合交易测试:
综合基准测试:
稳定测试:可靠性测试,平均无故障时间越长,修复时间越短越好。
性能测试:特定的负载条件下的性能指标数据。
不加think time接收的压力大
计算性能时还要取消think time
PV可以刷,按照访问次数
IP访问,按照IP计算
吞吐量KB:单位时间接收请求后返回的数量,在对比、评估类测试Tomcat比Weblogic

性能需求:
功能点:一次交易有多个功能
业务:一次交易为一次业务
交易:和服务的一次事件
提取性能需求:1.并发数 2.用户频繁使用,或存在大量用户使用 3.对于被测对象很熟悉是否有必填
性能测试不做异常分析和测试
对于架构熟悉,对于网络部署熟悉

性能分析:
1.分析被测对象业务规模
注册1W,交易数800左右,峰值交易时间段20分钟完成400左右,峰值并发30
2.分析测试点
a、注册
根据业务规模分析,每天交易量在800左右,意味着至少有800个用户登录,系统存在账号,测试1W,分解每天。另外,用2、8分析时间内最高访问量,集中发生的时间。
b、登录
某个时间点完成400次交易,单次登录消耗的时间?要求不超过3s
c、订票
d、查询
3.确定对应指标

并发数:
查询峰值得到并发数:使用SQL,使用count函数,datepass。
根据业务量计算并发数:10个注册成功案例,2分钟做完,需要几个人,一个用户消耗60s时间
HttpWatch打开后进行时间统计,利用loadrunner计算时间,
几个人就是并发数。
启动Server,如果报错可以陪着config
hp\laodrunner\webtours\conf\httpd.conf的#ServerName localhost:1080的#去掉,再启动服务
可以用HttpWatch计算登录时间,或者使用loadrunning计算
启动Virtual User Generator.exe
打开create a new script
打开web-http/html

打开首页,输入,提交,退出。

open_index
submit_login
sign_off

create a new script action
deleting the default action
click the recording button
setting the content of the URL address
strat recording
switch the action when the recording is completed
operating browser
close the recording when all operations are done 
Modify think time seconds
replay test
actioning think time and wasted time
click test results
select expand all
modify session:

单次登录11s

日均200WPV
200*80%=160W
24小时*20%=4.8小时
单次登录2s
一个用户4.8*3600s/2=8640次

测试4.8小时能否完成160W以上请求。
===================================================
系统要求5分钟(300s)内完成200次用户注册,响应时间不超过3s,成功率100%,cpu以及内存使用率不超过70%
单次注册消耗时间10.86s

open_index
into_register
submit_register

300s/10.86=27次
200次/27次=8个Vuser
8*27次=216个测试数据
216*1.2倍=260个测试数据

准备测试数据

响应时间:服务器处理时间(经验值2,5,8,10)2秒最好
==================================================
#define定义常量
#define COUNT 100
Action()

函数:
int sum(a,b){
  int x,y,z;
  x = a;
  y = b;
  z = x + y;
  return z;
}
Action(){
  lr_output_message("%d",sum(20,30));
  return 0;
}

条件:
Acton(){
  int random;
  random = rand()%3 + 1;//1,2,3随机
  switch (random){
    case 1:
      lr_output_message();break;
    case 2:
      lr_output_message();break;
    default:
      lr_output_message();
  }
}

循环:
Acton(){
  int i = 1, sum = 0;
  int count;
  do {
    sum = sum + i;
    i++;
//  count = i;
  }while(i<=10);
//  lr_output_message("%d",count);
    lr_output_message("%d",sum);
    return 0;
}

可以用字符数组表示字符串char test[] = "afasdfd";
指针:变量的地址。
指针变量:专门存放变量地址的变量。int *p1,*p2;float *q;
&取地址符号(p1 = &i),*p1取指针变量的内容。

如果使用一个脚本创建100个账户,可以迭代100次。也可以使用10个虚拟用户,每个用户创建10个账户。但是要设置parameter 里面unique并且设置Allocate Vuser values in the Controller为 Allocate 10 values for each Vuser。

参数Unique Number:当选择%03d,查看sample为001,block是数据块的意思,如果输入10就是001-010个数字也就是一个虚拟用户使用10个数字。另外使用拼接,可以"t{username}"。这样就是少一些参数输入。

=============================================
lr_output_message("第一次:%s",lr_eval_string("{paramtest}"));
lr_output_message("第二次:%s",lr_eval_string("{paramtest}"));
=============================================
增加检查点:需要点击Snapshot界面,选择Honzontal下的Recording,同时选择Page View下的要检查的部分右键选择Add Text Check Step,进入Find Text界面选择Save count复选框并在后面填写标志位regsiterflag。
在代码内添加Replace with Parameter,只需要右键选择对应几个字母,即可参数化之前设置好的参数。
命一个int regsitercount=0; 然后regsitercount = atoi(lr_eval_string("{regsiterflag}"));
if(regsitercount>0)lr_output_message("success");else "fail + %s",lr_eval_string("{username}");
检查点中的Add Text Check Step,如果在Page View下右键找到有可能不是真正要检查的字符。需要进入Http Data下的对应请求的Raw Data内HTML页面代码,找到对应的正确代码才可以。
==============================================
关联函数:
查看前台页面代码,可以看到name="userSession"。
定位提交表单的页面右键,点击属性,可以查看对应的url,变然后查看Http Data,就可以查看到userSession的位置。
web_reg_save_param
==============================================
open_index submit_login into_flight find_flight select-flight pay_flight sign_off
账户需参数化,username和userSession。出发到达城市随机。随机某个具体航班。
如果成功,还要测试失败是否也生效,代表是否正确的代码。
web_reg_save_param("usersession","LB=userSession\" value=\"","RB=\"/>",LAST);
web_reg_find("Text=Welcome","SaveCount=loginflag",LAST);
if(atoi(lr_eval_string("{loginflag}"))>0)//lr_eval_string转字符串,atoi转int
lr("success");
return 0;
else
lr("fail");
return -1;

web_reg_save_param("flights","LB=\">","RB=</option>","ORD=ALL",LAST);
自带随机函数lr_paramarr_random("flights");

char *departcity,departcitys[30];
char *arrivacity,arrivacitys[30];
departcity = lr_paramarr_random("flights");
lr("%s",departcity);
sprintf(departcitys,"Value=%s",departcity);把Value=departcity变为departcitys变量

可以直接更换Value=、、、为departcitys。

设置{departdate}进入Parameter List中选择Parameter type为Date并可以更改%a/%d/%y为%Y,就是年的全称2018。

web_reg_save_param("fightline","RB={departdate}");
char *flightno;
char flightnumber[25];
flightno = lr_paramarr_random("flightline");
如果判断参数的关联:sprintf(fligghtnumber,"Value=%s%s",flightno,lr_eval_string("{departdate}"));

另外一种取随机数:
int flightcount;
int departrandnum=0;
flightcount=atoi(lr_eval_string("{flights_count}"));
departrandnum = rand()%(flightcount/2)+1;
sprintf(departstr,"{flights_%d}",departrandnum);
lr(lr_eval_string(departstr));

SPDY
Google开发的基于TCP的应用层协议
Application        --- HTTP
Session            --- SPDY
Presentation(仪式) --- SSL
Transport          --- TCP

WebSocket
在 WebSocket API,浏览器和服务器只需要做一个握手的动作,然后,浏览器和服务器之间就形成了一条快速通道。
1. Header
互相沟通的Header是很小的-大概只有 2 Bytes
2. Server Push
服务器的推送,服务器不再被动的接收到浏览器的请求之后才返回数据,而是在有新数据时就主动推送给浏览器。

Clint-Headers
Request-Line:GET/HTTP1.1
Accept:text/html
Accept-Encoding:gzip
Accept-Language:zh-cn
Connection:keep-alve 保持长连接
Cookie:BAIDUID
Host:www.baidu.com
User-Agent:Mozilla

Headers-Received
Status-Line:HTTP1.1 200 OK
...

content:渲染后代码...

linux:内存swap 有些程序长时间不操作,或物理内存不足启动swap。
内存paging时时刻刻发生操作。
TCP 三次握手四次挥手
netstat -ae|grep "TIME_WAIT" |wc –l查看网络中time_wait修改配置文件排除问题。

httpwatch:查看,支持自动化API查询。Fiddler:本身代理Composer下的Parsed,可以拉拽一次协议查看并修改,端口8888,Inspectors下的Raw就是旧版的请求。并且可以测试https,需要Tools下的Fiddler Options下的https traffic。并且可以自定义服务器返回。firbug:修改前台界面。colasoft:从网卡读取数据。

netstat -ano,列出所有端口的情况。
tasklist | findstr "8888"

相应时间:客户端65535、网络、应用服务器、数据库
1.DNS 2.Connect 3.Send 4.Wait
清楚DNS ipconfig /flushdns

网络三个层次:核心层、汇聚层、接入层
网络吞度量,网络设备连接

应用服务器:
程序的健壮,小号资源合理
启动压缩(压缩文本而非其他)
缓存
预热
线程配置

数据库:
索引是否正常使用(db2分区键)
SGA是否分配合理
多用关联少用in
集合操作能用union all就不用union

最后客户端接收数据进行渲染

性能指标有多个站在用户和开发两个方面:运行程序占用,访问量,持续服务,相应时间
开发:涉及合理,安全,效率,回收,扩展,readme等
top:cpu:load average 5 15分钟负载(负载不能比CPU核数4倍还多)
负载阶段:规划、创建脚本、定义场景、执行场景和分析结果。
并发与并行、并发用户数和在线用户数、TPS和响应时间、点击数、吞吐量、资源使用率、PV和UV
并行:真的同时执行,CPU多核同时进行任务。
并发:不一定同时执行。因为有CPU有中断,所以感觉单核可以做多个任务,实际没有并行。
并发用户数:有效的负载用户。要一直操作。
在线用户数:包括操作和不操作用户。
transaction per second:每秒事物。每秒业务数。
相应时间:客户端+网络+服务器
点击数:发出请求数。
吞吐量:单位时间被处理的业务或者请求量。
资源使用率:%
PV:一个URL,访问量。
UV:一个用户,访问ip数量。
测试工具的协议才会造成负载!
通信协议:标准协议、自有协议
工具要有更新才有生命力,才学。
跨平台的工具才是好工具。
loadrunner jmeter Gatling IBM RPT was silk-performer
协议:Web SOAP FTP JDBC 等

问开发,经验,看项目文档,协议探测器(loadrunner自带)
选择协议,选择的是与压力模拟直接交互的中间件或者服务器,和后面的无关。再次强调,loadrunner录制只与协议有关,和操作界面关系不大。

1.界面简单解析 2.保存目录解析 3.脚本结构解析
vuser_int()
lr_output_message("");
action()
vuser_end()
Replay Log再运行脚本log
Generation Log程序抓包的协议日志

Tree可以树状图显示过程,选择HTTP View,但是显示慢。一般scrip即可。筛选的时候可以选择tree模式,筛选包的时候可以选择。

Replay Log中显示运行时设置文件:Run-Time Setting file:

建立脚本后必须要保存,才能存入。.usr即可调取LR的脚本界面。
mdv.log,output.txt是Replay Log
default.cfg 是运行时设置文件
.bak是副本。.asc录制的原始API调用。.grd包含数据库脚本中网络的列标题。default.usp保护脚本的运行逻辑,包括操作部分的运行方式。

F4配置number of iterations迭代次数action的次数,也就是业务的代码,实际不停操作部分。

C语言的main函数由LR去控制。

录制选项:Gerneral Recording中HTML-based script和URL-based script
HTML-based script:生成多个cookie,和一个函数,看不出过程。高级部分:Script type:A script describing user actions 模拟用户先打开界面,才能发送表单,注释开始会报错。和 A script containing explicit URLs only 直接把表单提交到服务器,注释开始打开页面后面不会报错。
URL-based script:生成多个cookie,和每一个包都的URL都列出来,所以看出所有的过程。高级部分:

注释Ctrl + Alt + C

录制选项:HTTP Properties Advanced中UTF-8可以中文输出log。

事例jojo/bean

大部分使用的都是URL的方式:
基于浏览器的推荐使用HTML录制,客户端的推荐URL录制。
但是如果浏览器内有js多次请求,有可能抓不到请求,就需要URL录制。
当使用HTTPS,推荐使用URL的方式。

运行时设置文件:Run-Time Setting file:的解析。
可以选择是否使用思考时间。
可以设置使用多大带宽,一般使用最大带宽。
browser的设置browser emulation:
HTTP的协议会有这个字段User-Agent:数值可以选择或者直接写入value。
为了LR看到User-Agent需要打开扩展日志:log---extended log---Data returned by server并且选择---advanced trace 即可在日志中看到
User-Agent根据后台校验的时候需要修改。
Simulate browser cache可以启动,也可以不启动,会在日志中显示。
Cache URLs requiring content把内容缓存和Check for newer versions of stored pages every visit to the page
这两个都是更好的模拟浏览器。内存够用就启用URLs。Check可以模拟浏览器点击刷新动作,RL会添加请求头选项if-modified-since
,校验更新时间,是否需要更新,会不停询问,但是只能是页面内容,而图片不可以。
如果按两次F5浏览器会除去cache返回大量减少。
download non-html resources 下载非HTML资源,不勾就简化只下载html。
Simulate a new user on each iteration 每次都运行三次握手四次挥手。

C编程:
LR是解释型C语言。90%可以适用。
使用变量要提在最前一次性声明!不能在后面定义。
错误:
int a = 10;
printf("%d",a);
int b = 10;
编译错误!
全局变量global和局部变量(action end init)

char *p;
p = (char*)malloc(1024*sizeof(char));
free(p);

变量使用前,尽量初始化。
指针:
char var='A';
char *p=&var;
char *name = "LoadRunner";
l_o_m("var=%c",*p);//*p=p的内容,输出:A
l_o_m("name=%s",name);//name=指针,输出:LoadRunner
l_o_m("name=%s",*name);//输出:L
return 0;
%d输出整型 %c输出一个字符 %s输出所有字符串,因为字符串""是有/0做为最后一个标记,所以会输出所有字符串。

数组:
char p[]={'A','B','C','D'};//字符数组是没有/0,输出:ABCDLoad Runner!
char s[]="Load Runner!";//输出:Load Runner!
l_o_m("p=%s",p);
l_o_m("p=%s",s);
return 0;

c就是数组的首地址,但是字符数组是没有/0,所以会继续下面的内容,所以能不用字符数组尽量不用。

char s[]="Load Runner!"
sizeof(s)查看s的电脑识别长度多一个(包括/0一个长度),strlen(s)查看s的看到的长度。

a[1]="a"会造成会继续下面的内容(包括/0一个长度),所以能不用规定数组长度尽量不指定长度,使用a[]="abc"。

if(m==0)
{}
else
{}
for(i=0;i<5;i++)
{}

通用函数:lr_output_message("");
与编程语言相关的函数:%d %s
与协议相关的函数:
本身三个函数可以互相调用
vuser_int()
action()
vuser_end()
并且LR可以选择add files to script添加一个.h的文件,可以在右侧的global.h下面显示出来,还必须在action()的上面#include 'aaa.h',强行引入aaa.h的函数。
可以F1调用help,比如lr_think_time(),lr_get_host_name(),lr_whoami()获得详细信息,lr_get_attrib_string获得属性的字符串,可以返回一个指针,函数的使用方法:1通过运行时设置使用,2通过命令行
lr_get_attrib_string需要全局变量F4的additional attribute添加全局变量,如:hello:lr。
char *p = lr_get_attrib_string("hello");
可以输出lr

真正压力执行程序调用mmdrv.exe来执行脚本!
可以使用命令行执行:
"C:\Program Files\HP\LoadRunner\bin\mmdrv.exe" -usr C:\getparam\getparam.usr -out C:\getparam\result\ -hello loadrunner -loop 1
打印出loadrunner,和上面的hello:lr相似,就是可以直接用命令来调取lr_get_attrib_string的函数结果。直接修改脚本内容的变量!

LR可以设置错误的处理方式:General下的Miscellaneous,不勾易出错误中断;和Preferences下的Advanced下的Non,不勾易出错误中断。

在LR中运行时选择QTP脚本,为QTP脚本存放目录下文件扩展名为.usr的文件。
test.usp :包含脚本的运行逻辑包括actions部分的运行方式
在全局变量中:preferences---Non-critical resource errors as warnings可以把所有的报错输出,但是后面就不再执行了。
可以使用:miscellaneous---continue on error就可以继续执行后面的程序。
lr_continue_on_error(0或者1)可以详细设置处理错误的时候是否继续,默认是退出,而且会覆盖全局变量的错误方式设置。
lr_continue_on_error(1)
不再考虑出现错误
lr_continue_on_error(0)

lr_output_message---详细输出,哪里都会写入。
lr_log_message---只将message写入到本地,不输出到远程controller。
lr_message---只将message写入到本地,不输出到远程controller。
lr_error_message---红色输出,详细输出。

真正运行的时候要最小,只收error错误的日志,减少干扰。所以建议选择Log下的Standard log。
F10可以一步一步调试操作。可以设置断点,还有右键代码可以定位生成的日志信息。还有右键可以打开目录。

strcpy与strcat 从头添加和从尾添加
strcmp函数 比较两个字符串,相等返回零,1大于2返回正,1小于2返回负数。
atoi函数解析
sprinf
time

action(){
  char fullpath[1024],*filename = "logfile.txt";
  strcpy(fullpath, "c:\\tmp");
  lr_output_message ("fullpath after strcpy: %s", fullpath);
  strcat(fullpath, "\\");
  strcat(fullpath, filename);
  lr_output_message("Full path of file is %s", fullpath);

  return 0;
}
Action.c(12):fullpath after strcpy: c:\tmp
Action.c(18):Full path of file is c:\tmp\logfile.txt

action(){
  int i=0;
  char * s = "7 dollars";
  i = atoi(s);//转换为数字7
  lr_output_message("Price $%d", i);
  return 0;
}
Action.c(10):Price $7

Action(){
  int index = 56;
  char filename[64], * suffix = "txt";
  sprintf(filename, "log_%d.%s", index, suffix);//拼接
  lr_output_message("The new file name is %s", filename);
  return 0 ;

}
Action.c(10):The new file name is log_56.txt

Action(){
  typedef long time_t;
  time_t t;
  //Get system time and display as number and string 
  lr_message ("Time in seconds since 1/1/70: %ld\n", time(&t));
  lr_message ("Formatted time and date: %s", ctime(&t));
  return 0;
}
Time in seconds since 1/1/1970: 1416760912
Formatted time and date: Mon Nov 24 00:41:52 2014

与协议相关的函数
web_link与web_url(get)link只能有上下文关系,但是url可以直接。get的请求体没有信息,只有请求头,并且放入到url,限制了字数和保密缺陷,post却有请求体。
web_submit_form与web_submit_data(POST) web_submit_form中的hidden自动发送,post的请求。
web_custom_request//万能的,灵活并复杂,可以选择URL-based script 高级内选择Use web_custom_request only。
web_add_header web_add_auto_header //遇到自定义请求头的时候,使用比较好。
web_get_int_property//可以拿到详细的信息

Action(){
  web_add_header("gggg","loadrunner");
  web_url("WebTours",
    "URL=htt://127.0.0.1:1080/WebTours/",
    "TargetFrame",
    "Resource=0",
    "RecContentType=text/html",
    "Referer=",//从哪里链接过来
    "Snapshot=t1.inf",//LR的快照信息
    "Mode=HTML",
    LAST);//结束
  lr_think_time(3);
}
GET /WebTours/ HTTP/1.1\r\n
gggg: loadrunner\r\n

Action()
{int HttpRetCode;
web_url("my_home",
  "URL=http://my_home",
  "TargetFrame=_TOP",
  LAST);
HttpRetCode = web_get_int_jproperty(HTTP_INFO_RETURN_CODE);
if(HttpRetCode == 200)
  lr_log_message("The script successfully accessed the My_home home page");
  else
  lr_log_message("The script fialed to accessd the My_home home page");
}

在脚本的任何系统的函数中,不能使用C语言的任何函数。但是在系统函数之间是可以使用任意C元素。否则会报错,只能使用LR的制定参数等。

lr_load_dll函数的使用(可以引入外部.dll的函数),另外因为LR是解释C,所以如果用复杂的函数会很慢,所以最好压缩或者转dll的编译文件,再引入:
vuser_init(){
  lr_load_dll("c:\\loadDll\\md5.dll");
  return 0;
}
函数原型:
char* Calculate(const unsigned char* pachSource,unsigned int nLen)
第一个是要加密的字符串,第二个是该字符串的长度。
action(){
  char *p = "LoadRunner";
  int len = strlen(p);//计算字符串长度
  char *result = (char *)Calculate(p,len);
  lr_output_message("结果是:%d",ressult);
  return 0; 
}

事务和参数化
添加事务lr_start_transaction("openindex");
结束事务并计算时间:lr_end_transaction("openindex");
但是要配对,如openindex。
Action(){
  int status;
  lr_start_transaction("openindex");
  status = web_url("WebTours",
    "URL=htt://127.0.0.1:1080/WebTours/",
    "TargetFrame",
    "Resource=0",
    "RecContentType=text/html",
    "Referer=",
    "Snapshot=t1.inf",
    "Mode=HTML",
    LAST);
  if(status == 0)
  lr_end_transaction("openindex", LR_PASS);
  else
  lr_end_transaction("openindex", LR_FAIL);
  return 0;
}

Action(){
  lr_start_transaction("openIndex");
  web_url("WebTours",
    "URL=http://127.0.0.1:1080/WebTours/",
    "Resource=0",
    "RecContentType=text/html",
    "Referer=",
    "Snapshot=t1.inf",
    "Mode=HTML",
    LAST);
  lr_set_transaction_status_by_name(LR_FAIL, "openIndex");
  lr_end_transaction("openIndex", LR_AUTO);
  return 0;
}
Action.c(19):Notify:Transaction "openIndex" ended with "Fail" status (Duration:2.3595 Wasted time:1.3553).
duration是总共的时间
Wasted time是LR使用的时间,但是没有自编程脚本的时间没有加入到Wasted time,而且Controller和Analysis的时间是两个数减去的时间。

Action(){
  lr_start_transaction("openIndex");
  web_url("WebTours",
     "URL=http://127.0.0.1:1080/WebTours/",
    "Resource=0",
    "RecContentType=text/html",
    "Referer=",
    "Snapshot=t1.inf",
    "Mode=HTML",
    LAST);
  //lr_think_time(1);
  lr_output_massage("Duration = %lf -- Waste = %lf",
    lr_get_transaction_duration("openIndex"),//获取duration
    lr_get_transaction_wasted_time("openIndex"));//获取wasted_time
  lr_end_transaction("openIndex", LR_AUTO);
  return 0;
}
Action.c(17):Duration = 4.394222. -- Waste = 2.372381
Action.c(24):Notify:Transaction "openIndex" ended with "Fail" status (Duration:4.3595 Wasted time:2.3553).
think_time对于Duration有影响。

lr_wasted_time(wasteTime*1000);1000是毫秒
Action(){
  merc_timer_handle_t MasterT, timer;
  char save[1000];
  double wasteTime;
  int i;
  lr_start_transaction("openIndex");
  web_url("WebTours",
     "URL=http://127.0.0.1:1080/WebTours/",
    "Resource=0",
    "RecContentType=text/html",
    "Referer=",
    "Snapshot=t1.inf",
    "Mode=HTML",
    LAST);
  timer = lr_start_timer();
  for(i=0; i<(l * 1000); ++i)
    sprintf(save, "This is the way we waste time in a script = %d", i);
  wasteTime = lr_end_timer(timer); //return as msecond

  lr_wasted_time(wasteTime*1000);//把wasteTime也加入到wasted_time内

  lr_output_message("Duration = %lf -- Waste = %lf",
    lr_get_transaction_duration("openIndex"),
    lr_get_transaction_wasted_time("openIndex"));
  lr_end_transaction("openIndex", LR_AUTO);
  return 0;
}
Action.c(37):Duration = 10.627309 -- Waste = 9.282772//是LR加wasteTime的总共wasted_time时间。
Action.c(44):Notify:Transaction "openIndex" ended with "Pass" status (Duration: 10.6391 Wasted Time:9.2828)

lr_start_sub_transaction 提交子transaction,可以嵌套事务

具体事务中前台,bean,数据库各自浪费的时间不清楚,但是只知道总的和是事务时间。

参数化:
Action(){

  web_submit_data("search",
    "Action=http://www.youdao.com/search",
    "Method=GET",
    "EncType=",
    "TargetFrame=",
    "RecContentType=text/html",
    "Referer=http://www.youdao.com/",
    "Snapshot=t2.inf",
    "Mode=HTML",
    ITEMDATA,
    "Name=q", "Value=test", ENDITEM,
    "Name=ue", "Value=utf8", ENDITEM,
    "Name=keyfrom", "Value=veb.index", ENDITEM,
    LAST);
  return 0;
}
那些可以参数化:可以查看F1找到parameterization,只能参数化LR的函数内的参数。
需要参数化:
1.登录 2.一些和时间相关的,违反时间约束的 3.一些受其他字段约束的 4.一些来自其他数据源,例如数据库 5.其他在运行过程中需要变动的。
在Tools内General Options中Display 点击Show run-time viewer during rep 点击Auto arrange windo可以打开显示操作过程展示

选择需要参数化的范围右键,可以选择Replace with a Parameter,可以选择类型,或properties详细设置。
设置好后在代码会显红并且用{}括起来。

在General Options中Paraneterization中设置使用什么符号括起来。

如果想看到参数化,必须在log中Extended log 中 Parameter substitution勾选。

进入properties详细设置:可以设置数据的行和列,并且导入数据库,选择数据如何读取,设置一行数据用逗号隔开。如果有数据1,创建数据二后选择数据1可以关联,如用户名关联密码。

参数化会在保存目录内生成.dat的文件。并且最后一个肯定有一个回车空行。

什么时候改变参数化,其实就是如何切割数据池
select next row:获取下一行数据的方式:顺序,唯一(只能选择一次)和随机,特殊两个数据关联same line as username但是必须使用一个username的dat数据。
update value on:重新获取下一个参数的时机(条件):每次迭代,每次遇到和永远不变
when out of value:不够用数据的时候:循环,报错和用最后一个值

Unique,独特,代表一次选择后,后面不再选择。
when out of value 当数据不够用的时候
abort Vuser 失败结束
Allocate Vuser values in the Controller,如何分配数据块,可以自动按顺序,或者每3个选择一个块。
Unique并且Once,那么一个用户就用一个数据。

File还可以更改random number会用的比较多,就是随机从1-99

实例:保证用户名和密码配对

Action(){
  int a = 10;
  lr_output_message("变量的取值是:%d",a);
  lr_output_message("参数的取值是:%s",lr_eval_string("asd{output}"));
  return 0;
}
Action.c(5):变量的取值是:10
Action.c(7):参数的取值是:asd1

1.参数化和变量的区别:参数作用域远远大于局部变量,在一个action中的参数可以再另一个函数使用,而局部变量不行,除非是全局变量。
2.参数和变量的转换:1参数转换成变量 lr_eval_string(参数转变量) 2变量转换成参数 lr_save_string(把谁,转成参数谁)

Action(){
  char name[]="LoadRunner";
  lr_save_string(name,"aaa");
  lr_output_message("参数的取值是:%s",lr_eval_string("{aaa}"));
  return 0;
}
Action.c(8):参数的取值是:LoadRunner

但是这个参数无法从Parameter List中不会有显示。
数据库的连接也是从数据库中load到本地,所以可以连接JDBC等驱动获得。Sepacify SQL statment manu 是可以自己选择sql语句。

关联服务器变化参数
LR只能判断从协议上没有问题,但是实际业务是无法判断的。
1.所有验证都肯定在输出请求之前,就已经获得了。
2.如session、X-CSRFToken等
3.可以类比,或确定知道后,在tree模式下,找到对应请求的值,右键选择值,选择Create Correlation,在脚本中会出现CorrelationParameter_1的参数,直接使用{CorrelationParameter_1}放到对应的函数的session值,就可以直接安装响应取值。

查看函数web_reg_save_param_ex()中需要注意LB RB 左右侧标记,只要左右边界都唯一,就可以标记session。参数Scope可以选择body all等或者head,就是区域值。
reg是注册函数,必须放在关联的参数上面,先生成这个函数才能关联成功。

4.大部分都是hidden的type,并且放到请求头。X-CSRFToken,跨站点保护参数。
web_reg_save_param("X-CSRFToken","LB=X-CSRFToken\" value=\"","RB=\"","Search=Body","Ord=1",LAST);
X-CSRFToken\" value=\"是左边界
\"是右边界,就是双引号
Ord=1是如果搜索到多个,选择第一个
日志log的参数也需要打开

5.最好使用Fiddler的Composer来模拟排查,录制后直接鼠标拖拽。
寻找失败点后面的页面请求,把成功的网页请求放到Fiddler,并且删除猜测的检查数值。直到出现相同的返回错误代码,基本可以找到。

同样在LR中也可以使用web_add_header来篡改请求。

6.一般变化中无效验证:Referer之前源跳转网址等。

7.每一步,都要查看是不是值有不同多次请求!
同时对于每个检查值都要记录,因为有时候同样的检查值会变化,不是一直都用一个检查值。前后做值的对比,查看是否有变化。

集合点的概念,解析集合点函数:选择insert的rendezvous,只能在action中添加集合点,事务中不要添加集合点,会停止事务。在controller并发的时候使用。

P27-P30
脚本开发的原则:简单、正确、高效
单用户循环一次,多次(Vugen)
多用户循环一次,多次(controller)

第十讲:
性能计划编写
1.1系统简介
1.2性能测试目的
1.3性能测试策略
2.1系统组成分析
对于错误用例也要注意服务器的状态

环境变化一定要和上级确定,需求一定要写邮件做证据。
计算并发可以估算:在线用户数*5%-20%
tps:每秒响应时间 2-8定律
准备工具:shell脚本或python脚本进行提取日志信息。

检查点:
尽量使用web_reg_find函数,不要中文,不能单单从协议层面判断。
web_reg_find("Text=jojo", LAST);
Action.c(24):Registering web_reg_find was successful

web_find("Text Check","What=Welcome",LAST);可以全文搜索。但是需要勾选Run-time Settings的Rreferences的Enable Image and text check

第十一讲
接口:协议HTTP POST GET
名词解释:
URL:
参数:
错误相应输出:
错误码定义:
例子:

vuser_init(){
  lr_load_dll("md5.dll");
  return 0;
}

  char secret_key[32] = "oweolsdoiowiwql";
  char api_key[32] = "zhangdanzhongxin";
  char method[32] = "datacenter.getBillGas";//开发的一个接口
  char timeOfSecond[12];
action(){
  char bd_sig[100];
  typedef long time_t;
  time_t t;
  springf(timeOfSecond,"%ld", time(&t));//拿到时间
  lr_save_string(timeOfSecond, "call_id");//字符串转参数
  lr_output_message("%s", timeOfSecond);//打印时间
  //bd_sig生成方式:MD5(api_key+call_id+method+secret_key))
  strcpy(bd_sig,api_key);
  strcpy(bd_sig,timeOfSecond);
  strcpy(bd_sig,method);
  strcpy(bd_sig,secret_key);
  lr_save_string((char*)Calculate(bd_sig,strlen(bd_sig)), "MD5");
  //lr_output_message("%s", md5);
  web_reg_save_param("return_code","LB=error_code\":\"","RB=\"","Search=Body","Ord=1",LAST);
  lr_start_transaction("selectGas");
  web_custom_request("t1",
    "URL=http://192.168.21.67:8080/openapi/datacenter?api_key=zhangdanzhongxin&method=datacenter.getBillGas&call_id={call_id}&bd_sig={MD5}&format=json&req_charset=utf-8"
    "&mobile=13800138000&period=201404"
    "&result_fields=All",
    "Method=GET",
    "Snapshot=t1.inf",
    "Mode=HTML",
    LAST);
  lr_end_reansaction("selectGas", LR_AUTO);
  //业务确定是否成功
  if(strcmp(lr_eval_string("{return_code}"),"0") && strcmp(lr_eval_string("{return_code}"),"300"))//比较函数,C语言中比较只能用函数
{
    lr_error_message("no 0 or 300, is %s, EXIT",lr_eval_string("{return_code}"));
    return -1;
  }
  lr_output_message("********************");
}

乱码出现:web_reg_save_param("error_code","LB=error_msg\":\"","RB=\"","Search=Body","Ord=1",LAST);
使用另外函数单独处理乱码:lr_convert_string_encoding(lr_eval_string("{error_code}"),
LR_ENC_UTF8,LR_ENC_UNICODE,"stringInUnicode");
lr_output_message("%s",lr_eval_string("{stringInUnicode}"));

如果由format=json变成format=xml,就需要调取web_reg_save_param_xpath();
tree模式对于xml模式支持比较好可以方便查看。
web_reg_save_param_xpath("ParamName=return_code","QueryString=//response/error_code",SEARCH_FILTERS,"Scope=Body",LAST);

启用controller,点击tools选择Create Controller Secenario。
可以选择Goal 或者 Manual,Manual可以选择多少个用户并发,选择负载生成器,建议虚拟机出一台专用负载机。

Design设计模式
两种模式:Show Convert Scenario Mode Warning转换为数量和Convert Scenario to the Percentage Mode转换为百分比
在Scenario Groups下的add Group添加脚本路径。
在Scenario Schedule下的Schedule by:Scenario 和 Group更多的设置选项。Scenario 把所有的脚本都作为一组统一调配,Group 可以更精细的设置在哪个组结束后开始这选定的一组,压力要慢慢加初始化,最后退出也建议缓慢退出。
在Scenario Schedule下的Run Mode:Real-world schedule更多的设置选项 和 Basic schedule。对于起伏的并发数测试,建议使用Real-world。但是一般测试选择Basic,除非是长时间稳定测试选择Real-world。
在Scenario Groups下的Run-Time Settings里面很像script里面的设置,但是各自负责各,不是通用。建议在运行错误在提示日志,think time默认是打开的,会执行script里面的think time时间。并且根据不同脚本地址也可以设置不同的设置。
保存的Design是.lrs文件,可以直接双击打开controller。

Run启动
把Available Graphs可以直接拖拽蓝色有数据的图标到界面。
可以直接点击Vusers...进行查看和操作。可以随时调节压力。
点击stop的时候Vuser的设置可以选择tools里面options里面Run-Time Settings,when stopping Vusers可以设置。

负载生成器
添加负载生成器选择Scenario下面Load Generators...。Name就是IP,添加后选择disconnect测试一下。
安装负载生成器后必须要启动,LoadRunner Agent Service。magentservice.exe就是负载生成器。
启动负载生成器后也要监视生成器的软硬件配置资源。

mmdrv
当Run-time Settings 里面的Miscellaneous 的Multithreading是以run vuer as a thread跑的时候,以50为一个mmdrv开始跑。但是以进程方式跑的时候就是几个vuser就几个mmdrv。以进程安全但是耗用资源,以thread不安全,可能共享内存,但是更节约。

IP欺骗 IP spoofer
更加模拟真实客户的不同IP,char *ip;ip = lr_get_vuser_ip();if(ip)lr_output_message("%s",ip);
还要选择Scenario下的Enable IP Spoofer设置。并且要在对应负责生成器上添加多个ip。必须要静态ip,选择高级,添加ip。LR也有工具可以添加负载生成器的ip,IP Wizard。

集合点
lr_rendezvous("myRende");可以查看scenario内的Rendezvous。可以控制vuser在某一时刻同时操作某一动作。当满足条件时同时释放。在Rendezvous内查看Policy,当所有正在跑用户到时释放,当所有用户包括失败的用户到时释放,当多少个用户到了再释放,等待到某一时刻释放集合点。

自定义数据采集
Note很重要
int i;
for(i=0;i<100;i++)
lr_user_data_point("cpu",i);

Analyze建议模板
数据保存access,文件是.mdb。启动Analyze可以直接点击controller的图标。打开后马上保存,下次打开会快很多。
Total Throughput(bytes):总吞吐量
Total Hite:总的http请求数
Transaction Summary下的Std.Deviation标准方差,反映是否足够平均分布,越接近平均值,STD越小。
左侧Properties内的Filter可以过滤。Percentile可以更改90%的数据统计。
Hits per Second 服务器每秒相应的http请求。左侧有Properties可以更改图表。
Throughput 网络的吞吐量:1Gb = 1000Mb 1Mb = 1000Kb,网络传输单位。硬盘也是1000GB,不是1000G,存储是Byte。1000Mb/8bit/Bye,8bit = 1Bye。1000M/8 = 125MB/s 也是理论每秒传输的存储量,实际1000M达到60%以上为负载。
Average Trans...esponse Time 平均事务的相应时间。会有问题,建议关闭再打开,左侧Graphs右键选择增加Graph。

Web Page Diagnostics
在reports里增加Graph,Page Downlo...Breakdown是清楚看到各个层的相应时间。
DNS Resolution DNS解析时间
Cronection Time 连接时间,TCP进行三次握手四次挥手
SSL Handshaking Time HTTPs才有SSL
FTP Authentication FTP服务器的时间
First Buffer Time 从发送请求到接受第一个请求的之间时间
Receive Time 接受时间,从第一个接收到最后一个接受时间
Client Time 客户端处理时间
Error Time
详细解释可以参考Analysis User Guide

图标的合并
拐点上是不可接受,也就是角度很大,过陡;拐点下是可以接受,也就是角度很小。
合并需要x轴单位一致。点击图表右键的Merge Graphs
Overlay 共享一个x轴
Tile 共享一个x轴,其中一个在上面。
Correlate 取消两个图表的x轴,并把两个y轴作为数轴x和y轴。方便查看拐点的图表。

可以生成报告,可以参考。

在Controller下生成的Transaction时间,可以初步判断是否有问题。
先在单脚本时估计一下,是否时间一样。如果一样,那就是单脚本的问题,不是controller并发的问题。

查看脚本是否规范请求。是否和真实场景一样。

如果有报错,要双击打开。

如果接口优秀,也会报错,可以增加think time,来让客户端负载生成器回收端口。并且在controller内也要设置think time的有效百分比。

查看数据库:mysql -q 
user datacenter
show tables
show create table Bill_Electric显示表的建表结构。
查看表缺少UNIQUE KEY '' () USING BTREE,联合组件。
alter table Bill_Electric add unique index AK_UK_Bill_Electric('AccountNo','Mobile','Period')USING BTREE; 表内加入组件。
show variables like '%query%';
set global slow_query_log=1;
set global log_queries_not_using_indexes = 1;

增加一些知识:数据库:安装重启,基本SQL语句,数据库架构,数据库原理,mysql的组建、引擎、man查询帮助、回表、联合索引,

空P43 第十三讲

新建脚本时,可以选择java内的java vuser。是编译的,所以要装JDK,错误提示更精确。Run-time Setting内的Java VM下的Use specified JDK,指定JDK为C:\jdk-1.6
全部写在action内,不要去其他地方写代码。
不足:有些语法支持不好,例如静态代码块,少用不常用的语法和功能。有时因为缓存,而需要切换JDK,才能正常。
不足如下:
class StaticBlock1{
  static{
    System.out.println("H");
  }

  public static void main(String[] args){
     System.out.println("L");
  }
}
out:H
out:L
静态代码块,会在new后马上开始执行,不需要调用。

只有一个类是public,定义class可以在任何位置。

如果需要引入外部的class文件,只需要把文件放入到保存的文件夹内,就可以直接new了。或者在Run-time Setting内classpath添加jar包。

注意:1.脚本中包括自定义的类,需要确保类是线程安全的,如果不确定,使用进程方式,可以充分隔离。
线程安全,同一个对象或变量,被线程争抢。没有修改肯定是安全的。线程安全是很难检测的,但是在大压力或者CPU资源紧张的时候相对容易发现。
import lrapi.*;
public class Actions{
  private static int iteration_counter = 0;
  public int init(){
    return 0;
  }
  public int action(){
    iteration_counter++;
   return 0;
  }
  public int end(){
    lr.message(iteration_counter);
    return 0;
  }
}
只能加锁
不要再LR内自己加线程,要LR来加线程。

开发Java Vuser:
1.是否使用(1.强大的开源类库。2.更方便使用开发的自定义的类。)
2.在eclipse中编写一个正确的模拟代码
3.将eclipse代码移到LR中
4.结合业务特点,对脚本进一步增强
5.使用Controller运行多用的JavaVuser

P46
一般遇到Socket使用java
public class Actions{
  private SendOverSocket sos = null;
  private String receiver = null;
  private int version;
  public int init() throw Throwable{
    sos = new SendOver
  }
}

从web脚本转化Java Vuser
1.使用sed.exe
2.将要转换的web脚本复制出来并保存到文本中
3.参数界定符部分需要由于{}手动改成<>
4.打开DOS
5.切换到C:\Program Files\HP\LoadRunner\dat
6.运行..\bin\sed -f web_to_java.sed c:\web.txt > c:\java.txt
7.创建参数并进行其他操作


第15讲--虚拟与现实的结合-探索Java虚拟机
Java虚拟机:
虚拟化技术:所谓虚拟化技术就是将事物从一种形式转变成另一种形式,最常用的虚拟化技术有操作系统中内存的虚拟化,实际运行时用户需要的内存空间可能远远大于物理机器的内存大小,利用内存的虚拟化技术,用户可以将一部分硬盘虚拟化为内存,而这对用户是透明的。
JVM的启动流程:
java xxx
装载配置寻找jvm.cfg
根据配置寻找JVM.dll:JVM.dll为JVM主要实现
初始化JVM获得JNIEnv接口:JNIEnv接口是为JVM接口,findClass等操作通过它实现。
找到main方法并运行。

查看虚拟机进程:
package com.test;
public class Test {
public static void main(String[] args) throws InterruptedException {
    System.out.println("************start*************");
    Thread.sleep(30000000);
    System.out.println("*************end**************");
}
}
查看任务管理器内启动javaw.exe *32

Java虚拟机运行时数据区结构图

http://www.catalannuan.com/2015/04/02/about-jvm/

系统资源监控
windows:
使用loadrunner直接监控,但是C盘必须能访问
使用性能工具

linux


 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章