-
Loadrunner脚本编程3- 检查点,关联等函数
2010-05-24 16:29:13
1. 错误预防和恢复参数默认是用{}括起来的,但也可以指定用<>
NTLM或用户登录验证
web_set_user("X\\Y", "Z", "A.com:80");
在域与X上的用户名为Y的用户,使用密码Z来登录到A.com:80。在windows基本验证的时候这个脚本被默认录制下来,但如果web服务器需要更安全的NTLM或更深层次的验证,需要手动的添加这个函数到脚本中。对于NTML验证,用户名必须在域名之后,并且以\分割。使用\等符号,需要使用\\,前面的\用来做转义用,否则会出现警告提示。
zibeike注:在论坛中也看到了一些朋友讨论windows弹出登录框的操作LR无法录制到,导致回放出错,一般出错信息多为“Error -26547: Authentication required, please use web_set_user, e.g. web_set_user("domain\\user", "password", "host:port"); [MsgId: MERR-26547]”,其实这种情况错误信息已经很明显的给你提示了,需要往脚本中添加web_set_user函数即可。
2. IP欺骗(略)
3. 验证检查点
通常脚本录制完后需要手动添加些脚本来来确保预期的操作确实进行了正确的响应(如在操作之后后验证显示的一段文本或者图片)。这些检查可以使用正则表达式。
Web虚拟用户脚本中不会录制到检查点,需要手动添加或者使用VuGen的用户接口来添加函数代码。
最常用的检查点函数是web_reg_find。这个注册函数会查找脚本中下一个操作如web_url后产生的一段文本。它是从返回的缓冲区扫描而不是在接收的页面中查找。这是比web_find更高效的一个函数。
可以使用下面的代码来验证文本出现的次数:
web_reg_find("Text=ABC", "SaveCount=abc_count", LAST);
web_url("Step", "URL=...", LAST);
if (strcmp(lr_eval_string("{abc_count}"), "0") == 0)
lr_output_message("not found");else
lr_output_message("{abc_count} found");
如果想保存并且显示找到的文本,可以使用web_reg_save_param界定左右边界把找到的信息保存到参数中。如下:
char *str1,*str2;
str1="desired text";
// Register the left and right beacons sought:
web_reg_save_param("param","LB/ic=xxx","RB=xxx");
// Do the monitored deed:
web_url("some url","URL=www.xxx.com",LAST);
// Compare:
str2=lr_eval_string("{param}");
if(strcmp(str1,str2)==0) {
lr_output_message("param found");}else{
lr_output_message("Value found is %s",str2);
}
zibeike注:1)这里想跟大家说下注册函数,在web/http协议的脚本中,注册函数均以web_reg为前缀,这种注册型的函数都是从缓冲区扫描或者获得数据,因此需要提前声明即需要在能获得该查找信息的函数之前添加这些注册函数。例如,web_url()请求了一个页面,我需要验证该页面中是否有某个特定的文本,那需要在web_url()函数之前加上web_reg_find,类似的还有关联的函数web_reg_save_para是一样的,需要放到能获得想要的数据的请求的函数之前。但如果想查看这些函数最终保存的结果,如想打印关联函数web_reg_save_para中保存的参数内容,打印的操作就需要放到请求的函数之后了。
2)web_find和web_reg_find的区别:前面的是查找页面显示的数据,因此需要放在请求页面的函数之后,而且查找的信息是显示的web页面上的信息。后者是注册型函数,需要放到请求的页面之前,而且查找的内容是服务器返回的缓冲数据中查找,所以查找内容应该看html源代码的内容。
基于HTML录制方式的代码,可以使用web_image_check对HTML页面中包含的图片进行验证。并且需要注意的是只有在Runtime Settings > Internet Protocol Preferences 选择了"Enable Image and text check" 检查点才有效。
-
Loadrunner脚本编程2
2010-05-24 16:26:20
Web用户Action
在VuGen中,脚本产生的默认模式是基于HTML的--“描述用户的动作的脚本”直接与用户的动作是对应的:* web_url是浏览器地址栏的URL.
* web_link是点击在<a href= P>
* web_image是点击HTML的<img href= P>
* web_submit_form. 是在前面操作的上下文中的GET或PUT表单上点“提交”--可能前面的操作被VuGen在基于HTML模式下录制下来了。
* web_submit_data 是在GET或PUT表单上点“提交”,而没有带前面操作的上下文--可能是在基于URL模式下录制,或者是基于HTML模式,并且选择了“A scrīpt containing explicit URLs only”选项。
不用HTML产生的资源是.gif和.jpg图片。资源属性的列表只能当对这些资源的路直选项设置成“Record within the current scrīpt step”时被插入。这也是默认的设置。
如果你在“Tools > Internet Procotol > Recording”中选择“a scrīpt containing explicit URLs only”,这将会产生URL-based的脚本录制,只使用web_url和web_submit_data函数,将不会使用 web_link 和 web_image函数,或包含在 applets, XML, ActiveX或javascrīpt中的非HTML元素。
在进行下一页录制之前(如点击链接或者图标),暂停录制,把该页屏幕的标题拷贝下来粘贴到注释中。录制完成之后,这将会在后面的给事务命名上用到。
在每一个页面显示之后,暂停录制,把决定是否是期望页的文本拷贝下来,粘贴到注释中。录制完成之后,这将会用到文本验证检查点的脚本编写中。
录制中产生的各种信息都保存在RecordingLog.txt文件中,删除它不会对脚本的回放产生影响。
额外录制的Action脚本
录制脚本的时候,当浏览器没有安装SSL根证书的时候,会捕获的下面这些代码行。这个信息意思是“这个证书不能被信任证书验证”。web_url("authrootseq.txt",
"URL=http://www.download.windowsupdate.com/msdownload/update/v3/static/trustedr/en/authrootseq.txt",
"Resource=1",
"RecContentType=text/plain",
"Referer=",
web_url("authrootstl.cab","URL=http://www.download.windowsupdate.com/msdownload/update/v3/static/trustedr/en/authrootstl.cab",
"Resource=1",
"RecContentType=application/octet-stream","Referer=",
LAST);
录制脚本的时候,但浏览器遇到Macromedia flash组件的时候,会产生下面的代码行:
"URL=http://fpdownload.macromedia.com/pub/flashplayer/update/current/xml/version_en_win_ax.xml",
"Resource=0",
"RecContentType=text/html",
"Referer=","Snapshot=t8.inf",
"Mode=HTML",
LAST);
web_url("version_en_win_ax.xml",
如果你安装有Google Toolbar,即使你没有访问Google,也会录制上发到Google的请求。
脚本语言规则:
在LoadRunner中,大小写是敏感的,甚至在被检验的值中。所以上面的脚本会因为大写字母的原因,不会识别“Welcome”的。所以Steve Cheney 建议使用“ic”忽略大小写的文字标志:
web_reg_find("Text/ic=Welcome",LAST);
括号里的参数包含了LAST 是为了指定最后的一个参数。这样做是很方便的,因为上面的例子漏掉了一个指定期望是“found”还是“notfound”的属性。默认是“found”,所有我经常忽略它。
另一个文本标志是“/BIN”用来指定是二进制的字符集。例如,查找“Adams”:
web_reg_find("Text/BIN=\\x00A\\x00d\\x00a\\x00m\\x00s",LAST);
注意两个反斜杠,一个是转义字符,代表是使用了一个符号。如果错误的只使用一个反斜杠,LR会认为它是一个空的终止。
下面的例子脚本是在UTF8服务器上支持获得newquoteuid为UTF-16编码。因为LoadRunner中,UTF16编码的“Red”用ASCII是 R\x00e\x00d\x00 这样的,所以需要把它保存到buffer中。
lr_eval_string_ext("{newquoteuid_temp}",
strlen("{newquoteuid_temp}") + 2,
&Buf, &BufLen, 0, 0, -1);
对字符数组变量NewBuf使用lr_save_var函数来去掉额外的填充(x00):
for (i=0; i if (Buf[i]!=0) NewBuf[NewBufLen++]=Buf[i];
lr_save_var(NewBuf, NewBufLen-1, 0, "newquoteuid");
注:lr_save_var 需要四个参数(不需要使用LAST)
1.param_value 参数值
2 value_len 参数的长度。
3 options 参数的选项,一般为0
4。param_name 参数名称lr_save_var
Saves a variable length string to a parameter.
lr_eval_string function.
Returns the string argument after evaluating embedded parameters.
The lr_save_var function assigns the specified variable length string to a parameter. This function is useful in correlating queries. To determine the value of the parameter, use the
LoadRunner 7.8不支持正则表达式,但是有他自己的通配符:
为了使任何[0-9] 的数字在指定的数字位置,使用/DIG做标志:
web_reg_save_param("pSer","LB/DIG=Serial XXX-###-ZZZZ","RB=\r\n", LAST );
有三种使用^做通配符的方法:
* 忽略大小写,并且允许在指定的字符位置使用任意字符:
web_reg_find("Text/ALNUMIC=^ercury", LAST);
* 允许任何小写字符[a-z] 在指定位置:
web_reg_find("Text/ALNUMLC=^ercury", LAST);
* 允许任何大写字符[A-Z]在指定的字符位置:
web_reg_find("Text/ALNUMUC=^ercury", LAST);
把一个字符串变成大写:strupr()
错误信息:
请添加一些其他的错误信息来帮助其他人:
Could not resolve address of host ... [MsgId: MERR-27798]
如果网络不能用或者域没有注册的话,显示一个404的DNS错误Contents unexpectedly not in cache. [MsgId: MERR-26549]
当一个文件为空时会显示该错误。在空文件中添加空格来满足LoadRunner的错误检查。BTW,因为当创建的iframe没有文件时,IE会产生一个错误,这样就指定了一个空文件。事务时间脚本编写:
我更喜欢给一个action命名事务,而不是一个结果页面。
lr_start_transaction("00.1 Invoke URL");
...
lr_end_transaction("00.1 Invoke URL",LR_AUTO);
...
lr_start_transaction("01.2 Top menu");...
lr_end_transaction("01.2 Top menu",LR_AUTO);
lr_start_transaction("02.0 Updating");lr_start_sub_transaction("02.1 Update menu","02.0 Updating");
web_url( ...
lr_end_sub_transaction("02.1 Update menu",LR_AUTO);
lr_start_sub_transaction("02.2 Update submit","02.0 Updating");web_submit_form( ...
lr_end_sub_transaction("02.2 Update submit",LR_AUTO);
lr_start_sub_transaction("02.3 Update OK","02.0 Updating");
...
lr_end_sub_transaction("02.3 Update OK",LR_AUTO);
lr_end_transaction("02.0 Updating",LR_AUTO);
我喜欢在一个层次结构中使用0填充的事务名称,这样来确保控制器能够正确的给事务排序。我对不同类型的action上的事务名称上加不同的关键字
Contact Link = Click "Contact" link on Menu
Contact Icon = Click "Contact" Icon
Regis. Sub = Page Submit
OK = Pop-up dismiss with OK
事务名可以是变量,但是它只能被VuGen作为字符串来编译,不能在控制器的接口中显示。无论如何,他们会显示在分析结果文件中。对于web脚本,LR自动创建和决定事务的的持续时间,但是C语言脚本可以使用这些函数:
使用lr_start_transaction_instance函数来显式获得指定事务实例的句柄,事务名称在函数lr_user_data_point_instance或lr_user_data_point_instance_ex中使用。
使用 lr_start_sub_transaction在一个事务中来操作思考时间和消耗的时间。
来自: http://hi.baidu.com/cbxm/blog/item/a7a8e9f56a6b0ee47609d7ba.html
-
Loadrunner脚本编程1
2010-05-24 16:16:33
就目前的了解。Loadrunner的脚本语言其实和C没什么区别。他内部的好多机制都是C实现的。
不过是一种“类C”
所以我从几个方面分析
1:定义常量变量和C一样
2:LR函数的参数使用与C有点不一样, 在LR中,C的变量和LR的参数是不一样的。
任何C的变量都不能被LR的函数直接调用。
应该用lr_eval_string来取值。3:什么循环语句,选择语句都和C一样
4:一些函数的定义和C不一样。虽然名字一样,参数有不同
5: 输入输出也有些不同。
所以重点要突破的地方就是理清参数和变量直接的关系。和多熟悉一LR些函数,其他就是C语言的知识了。lr它有自己管理的变量,也叫参数,这种参数只能通过reg或者lr_save_方式定义,或者通过文件定义.
1.参数的赋值和取值
lr_save_string("hello world","param");
lr_eval_string("{param}");
2.变量到参数
int x;
x=10;
lr_save_string(x,"param");
lr_eval_string("{param}");
3.变量读参数
char x[100];
strcpy(x,"{param}");
lr_save_string("hello world","param");
lr_log_message("%s",lr_eval_string(x));LoadRunner没有提供对参数的算术运算的函数。所以LR的参数必须:
1) 转换成C的整数
2) 使用C的函数来运算最后返回一个C的字符串
3) 把返回的字符串保存成参数
view plaincopy to clipboardprint?
// 1. 转换成C的整数:
i = atoi( lr_eval_string("{pNum_in}") );
// 2. 使用C的函数来运算最后返回一个C的字符串:
sprintf( cBuf, "%d", i+1);
// 3.把返回的字符串保存成参数:
lr_save_string( cBuf, "pNum_out");
// 1. 转换成C的整数:
i = atoi( lr_eval_string("{pNum_in}") );
// 2. 使用C的函数来运算最后返回一个C的字符串:
sprintf( cBuf, "%d", i+1);
// 3.把返回的字符串保存成参数:
lr_save_string( cBuf, "pNum_out");
lr_eval_string()函数的主要作用:返回脚本中的一个参数当前的值,
返回值类型:char
一般多用在调试脚本时输出参数的值.具体用法如下:
lr_output_message("The parameter1's value is %s",lr_eval_string("{parameter1}")),其中参数parameter1在之前已经定义了的参数lr_log_message(lr_eval_string("{parameter1}"))
在LR中,C的变量和LR的参数是不一样的。
任何C的变量都不能被LR的函数直接调用。
应该用lr_eval_string来取值。
比如{NewParam}(LR中参数化的变量)直接用这个引用是没有问题的。
但是如果如下:Action()
{
char a[10];
a="{param}";
lr_message(a);
return 0;
}这就不对了。
lr_message(a);就会报错。但是写成lr_message(lr_eval_string(a));就可以。Action()
{
char a[10];
lr_save_string("hello","param");
strcpy(a,"{param}");
lr_message("%s",lr_eval_string(a));
return 0;
}
因为这里的值已经取出来了。********** 参数和变量传递 ***********/
Variable( )
char* ip =lr_get_vuser_ip();//获取当前用户的IP地址,保存在IP变量里。
char* gname =lr_get_host_name();//获取当前用户的机器名,保存在GNAME变量里。if(ip)
/* 参数转变量 */ //RunTime是已定义的参数,下文也可以直接调用
lr_vuser_status_message("Ip地址: %s ,参数 : %s",ip,lr_eval_string("{RunTime}"));
else
lr_vuser_status_message("未启动IP欺骗……");/* 变量转参数 */
lr_save_string(gname, "GN" );//把变量IP存在“GN”参数里,下文可以直接用 {GN} 调用。
/* 参数输出 */
web_submit_data("StatusReporter",
"Name=title", "Value={RunTime}",ENDITEM,
"Name=content", "Value={GN}",ENDITEM,
LAST);
/* 变量输出 */
lr_output_message("当前IP地址: %s ",ip);lr_think_time(2);//停顿两秒便于观察。
return0;
}最初我想实现用web_reg_save_param()取到的数保存在数组中,并lr_eval_string()来显示数组中的各个元素。代码如下:
web_reg_save_param("test","LB=","RB=","ORD=All",LAST);
web_url();
count = lr_eval_string("{test_count}");
for (i=1;i<=count,i++)
sprintf(str,lr_eval_string("{test_%d}"),i);
但是每次得到的数据总是
str = test_1 test_2.....都不是数组中的元素。
其实这个问题就是没有搞懂lr中内部参数和外部参数的区别
web_reg_save_param()中取到的数组,是属于lr的内部函数,在其内部函数中再使用变量,即(test_%d,i),是不能直接取到元素的值。这个中间必须要通过变量(外部变量)来传递。
上述代码改为:
web_reg_save_param("test","LB=","RB=","ORD=All",LAST);
web_url();
count =atoi( lr_eval_string("{test_count}"));
for (i=1;i<=count,i++)
{
sprinf(tmp,"{test_%d}",i);
sprintf(str,lr_eval_string(tmp));
}
这样就能实现了。
lr_save_string
The lr_save_string function assigns the specified null-terminated string to a parameter. This function is useful in correlating queries. To determine the value of the parameter, use the lr_eval_string function.来自: http://hi.baidu.com/cbxm/blog/item/7bfed4ac972ab3024b36d6b9.html
-
再说“事务”
2010-05-23 23:24:38
从下面的例子我们可以得出几个结论:
只要是步骤都会消耗时间,包括lr_start_transaction(),lr_end_transaction()等
lr_get_transaction_duration:duration可以是lr_start_transaction到lr_get_transaction_duration之间,lr_stop_transaction到lr_get_transaction_duration之间,而transaction stop之前的时间不算在内
lr_stop_transaction:stop transaction之前的时间不计算
lr_resume_transaction:一旦resume transaction,那就要从start transaction开始计时
例子:
Action()
{
int i;
int iteration=100;
char aStr[100];
lr_start_transaction("stop&start");
for(i=0;i<iteration;++i)
{
sprintf(aStr,"%d",i);
lr_log_message("%d",i);
}lr_output_message("First time=%f",lr_get_transaction_duration("stop&start"));//0.985325=start transaction+iteration1
lr_stop_transaction("stop&start");
lr_output_message("Immediatly after stop=%d",lr_get_transaction_duration("stop&start"));//-1639921593
for(i=0;i<iteration;++i)
{
sprintf(aStr,"%d",i);
lr_log_message("%d",i);
}
lr_output_message("After stop and loop = %f",lr_get_transaction_duration("stop&start"));//0.991988=stop transaction+iteration2lr_resume_transaction("stop&start");
lr_output_message("After resume time=%f",lr_get_transaction_duration("stop&start"));//2.011729=start transaction from start transaction to here1
for(i=0;i<iteration;++i)
{
sprintf(aStr,"%d",i);
lr_log_message("%d",i);
}
lr_output_message("After resume and loop = %f",lr_get_transaction_duration("stop&start")); //3.124461=all the time from start transaction to here2
lr_end_transaction("stop&start", LR_AUTO); //3.1340=all the time from strart transaction to here3return 0;
}
-
事务Transaction
2010-05-22 22:09:08
对LoadRunner来说事务是非常非常重要的概念,具体如下所述:
1、事务是LoadRunner度量系统性能指标的唯一手段;
2、事务能够用于度量高风险业务流程的性能指标;
3、事务能够度量在一组操作中每一步的性能指标;
4、通过事务计时实现了不同压力负载下的性能指标对比;
5、通过事务计时可以帮助定位性能瓶颈;
从性能测试的 角度出发,我们需要知道不同的操作所花费的时间,这样我们就可以衡量不同的操作对被测系统所造成的影响。在脚本中插入事务的方法:
方法一:脚本生成后,手动插入事务;
注:事务命名必须具有实际意义,最好能表征步骤的业务含义,如login命名为"登陆",withdraw命名为"取款"等等。
方法二:在脚本录制过程中插入Start Transaction和End Transaction(推荐这种方法)
方法三:通过Run-time Settings中的Automatic Transactions自动生成事务
注:该种方法插入的事务仅能在LoadRunner Controller中的图表和报告中看到在脚本的log中看不到。事务函数:
lr_start_transaction 为性能分析标记事务的开始
lr_end_transaction 为性能分析标记事务的结束
lr_start_sub_transaction 标记子事务的开始
lr_end_sub_transaction 标记子事务的结束以便进行性能分析
lr_start_transaction_instance 启动嵌套事务(由它的父事务的句柄指定)
lr_end_transaction_instance 标记事务实例的结束以便进行性能分析
lr_get_transaction_duration 获取事务的持续时间(按事务的名称)
lr_get_trans_instance_duration 获取事务实例的持续时间(由它的句柄指定)
lr_get_transaction_think_time 获取事务的思考时间(按事务的名称)
lr_fail_trans_with_error 将打开事务的状态设置为 LR_FAIL 并发送错误消息
lr_get_trans_instance_wasted_time 获取事务实例浪费的时间(由它的句柄指定)
lr_get_transaction_wasted_time 获取事务浪费的时间(按事务的名称)
lr_resume_transaction 继续收集事务数据以便进行性能分析
lr_resume_transaction_instance 继续收集事务实例数据以便进行性能分析
lr_set_transaction_instance_status 设置事务实例的状态
lr_set_transaction_status 设置打开事务的状态
lr_set_transaction_status_by_name 设置事务的状态
lr_stop_transaction 停止事务数据的收集
lr_stop_transaction_instance 停止事务实例
例子:
Action()
{
long parent_trans_handle;
long child1_handle;
long child2_handle;
double trans_time;
int rc;
//lr_start_transaction_instance(const char *transaction_name,long handle);
//This function returns a unique long number which identifies the specific transaction instance. On error, a negative number is returned.
parent_trans_handle =lr_start_transaction_instance("ParentTransaction",0);
lr_output_message ("Parent transaction instance handle is %ld.", parent_trans_handle);
web_url("web_url",
"URL=http://www.51testing.com",LAST);
//lr_get_trans_instance_status(long transaction_handle);
rc = lr_get_trans_instance_status(parent_trans_handle);
lr_output_message("Parent Transaction status is %d.", rc);
if (rc == LR_FAIL) {
//lr_end_transaction_instance(long parent_handle,int status);
lr_end_transaction_instance(parent_trans_handle, LR_FAIL);
return;
}
//lr_start_transaction_instance(const char *transaction_name,long handle);
child1_handle =lr_start_transaction_instance("ChildTransInstance", parent_trans_handle);
lr_output_message("First child transaction instance handle is %ld.",child1_handle);
http://www.51testing.com/?114582/
web_url("web_url",
"URL=http://www.51testing.com/html/blog.html",LAST);
//lr_get_trans_instance_duration(long trans_handle);
trans_time = lr_get_trans_instance_duration(child1_handle);
lr_output_message("First child instance time is %lf seconds.",trans_time);
//get_trans_instance_think_time(long trans_handle);
trans_time =lr_get_trans_instance_think_time(child1_handle);
lr_output_message ("First child instance think time is %lf seconds.",trans_time);
//get_trans_instance_wasted_time(long trans_handle);
trans_time = lr_get_trans_instance_wasted_time (child1_handle);
lr_output_message("irst child instance waste time is %lf seconds.", trans_time);// tart_transaction_instance(const char *transaction_name,long handle);
child2_handle = lr_start_transaction_instance("ChildTransInstance",parent_trans_handle);
lr_output_message("Second child instance handle is %ld.", child2_handle);web_url("web_url",
"URL=http://www.51testing.com/?114582/",LAST);
//lr_get_trans_instance_duration(long trans_handle);
trans_time =lr_get_trans_instance_duration(child2_handle);
lr_output_message("Second child instance duration is %lf seconds.",trans_time );
lr_end_transaction_instance(child2_handle, LR_PASS);
lr_end_transaction_instance(child1_handle, LR_PASS);
trans_time =lr_get_trans_instance_duration(parent_trans_handle);
lr_output_message ("Parent Transaction duration is %lf seconds.",trans_time );
lr_end_transaction_instance(parent_trans_handle, LR_PASS);return 0;
}
我的栏目
标题搜索
我的存档
数据统计
- 访问量: 78654
- 日志数: 111
- 建立时间: 2007-09-07
- 更新时间: 2012-06-05