Action介绍:
1.一个Actions就是一个函数包,将用户操作根据类型存放在不同的函数中,当脚本生成的时候,会在对应的目录下生成:
vuser_init.c
Action.c
vuser_end.c
三个action.
每个action是一组功能的集合,默认的action包含独立的3个函数为vuser_init(),vuser_action()、vuser_end().
还有一个gloabls.h文件,用于存放全局变量,头文件内容等
2. action函数结尾处都有一个return 0 的命令,这是用来退出当前函数的。Return 0 说明该函数正常的结束,如果是非0值,可能表示非正常退出。
3.
Vuser_init函数:
一般将用户初始化的操作放在里面,如登录操作,分配内存等。
Action函数:
是虚拟用户要做的业务。用户的业务操作,也就是测试内容的主体。可以写多个action.c文件来作为业务操作流程
Vuser_end函数:
与Vuser_init相对应,Vuser_end做收尾工作,复位环境重置等。
4.通过运行结果我们可以想象LR的实现是这样的:
int vuser_init(){
}
int action(){
}
int vuser_end(){
}
5.数据类型:
类型 bit数 范围
Unsigned char 8bit 0--255
char 8bit -128--127 字符类型
Unsigned int 32bit 0--4294967295
Short int 16bit -32768--32767
double 64bit 1.7e-308--1.7e308
int 32bit -2147483648--2147483647 整型
unsigned long 32bit 0--4294967295
float 32bit 3.4e-38--3.4e38 浮点型
6. c语言无字符串的概念,只有字符类型
7.表达式:
1.#define 定义常量: 宏定义一个常量,常量的值是不可变化的
例如: #define COUNT 100
2.表达式语句
表达式语句由表达式加上分号“;”组成
例如:
Action()
{
int x,y,z;
x=20;
y=30;
z=x+y;
lr_output_message("%d+%d=%d",x,y,z);
lr_output_message("%d",z*COUNT);
return 0 ;
}
其中lr_output_message()函数为输出打印信息函数
%d表示整型数据
8.函数的调用语句
函数的调用语句由函数名,实际参数加上分号“;”组成
例如:
int sum(a,b) { int x,y,z; x=a; y=b; z=x+y; return z; } Action() { lr_output_message("sum = %d",sum(20,30)); return 0; }
9.条件语句
Action()
{
int random;
random = rand()%3+1;
switch(random)
{
case 1:
lr_output_message("random = %d",random);
break;
case 2:
lr_output_message("random = %d",random);
break;
default:
lr_output_message("random = %d",random);
}
}
其中random = rand()%3+1;中rand()为一个随机函数,%3取得是0,1,2;%3+1取得就是0,1,2,各加1为1,2,3;所以rand()%3+1表示取1,2,3;
例子:使用随机函数从1,2,3,4中随机随处一个数字做判断,如果为1则做加法,为2则做减法,为3则做乘法,为4则做除法,代码如下:
Action() { int x=0,y,z; x = rand()%4+1; //rand()%4表示使用rand()函数随机出现四个数,0,1,2,3;+1表示各个随机数加1,为1,2,3,4 //如果需要随机出3个数,则为%3 y = 4; z = 2; lr_output_message("x=%d",x); switch(x) { case 1: lr_output_message("执行加法运算"); lr_output_message("%d+%d=%d",y,z,y+z); break; case 2: lr_output_message("执行减法运算"); lr_output_message("%d-%d=%d",y,z,y-z); break; case 3: lr_output_message("执行乘法运算"); lr_output_message("%d*%d=%d",y,z,y*z); break; default: lr_output_message("执行除法运算"); lr_output_message("%d/%d=%d",y,z,y/z); } return 0; }
10.循环语句
switchaction() { int i=1,sum=0; int count; do{ sum = sum+i; i++; }while(i<=10); lr_output_message("1到10之间和为:%d",sum); return 0; }
11.for循环
forAction() { int i=1,sum=0; for(i=1;i<=10;i++) { sum = sum+i; } lr_output_message("1到10之间和为:%d",sum); return 0; }
12.字符串
C语言里没有字符串类型的数据,可以用字符数组来表示一个字符串。
例如 char test[] = "abcdefg";
示例:
charAction() { char test1[]={'a','b','c'}; lr_output_message("test1 = %s",test1); return 0; }
正确语法:
charAction() { char test1[]={'a','b','c'}; char test2[]="This is a test!"; lr_output_message("test1 = %s",test1); lr_output_message("test2 = %s",test2); return 0; }
错误语法:
charAction() { char test1[]={'a','b','c'}; lr_output_message("test1 = %s",test1); char test2[]="This is a test!"; lr_output_message("test2 = %s",test2); return 0; }
需要先定义完所有变量后,再运行往下,否则会报错误
13.
c语言中数组的名字代表某个元素的首地址
%s表示字符串的占位符
14.结构体
struct student { int num; //学号 char name[20]; //姓名 int score; //成绩 }; jiegouttiAction() { struct student stu[2]= { {101,"jack",100}, {102,"tom",90} }; int i; for(i=0;i<2;i++) { lr_output_message("-----------------------------------------"); lr_output_message("第%d个学生的信息:",i+1); lr_output_message("学号%d",stu[i].num); lr_output_message("姓名%s",stu[i].name); lr_output_message("成绩%d",stu[i].score); } return 0; }
15.指针
指针:一个变量的地址
指针变量:专门存放变量地址的变量叫指针变量
指针变量的定义:
一般形式:[存储形式]数据类型*指针名;
例如: int *p1,*p2,float *q;
&含义:取指针的地址&和*运算符
*含义:取指针所在变量的内容
zhizhenAction() { char test1='a',test2='d'; char *p1 = &test1; //给指针赋值 char *p2; //定义一个指针,未赋值 lr_output_message("p1=%c",*p1); //输出指针p1指向地址的内容 p2=&test1; lr_output_message("p2=%c",*p2); //输出指针p2指向地址的内容 *p2 = 'b'; lr_output_message("p1=%c,p2=%c,test1=%c",*p1,*p2,test1); test2 = *p2; lr_output_message("test2=%c",test2); return 0; }
16.其他的编程语言中是没有指针的,只有C语言中有
17.头文件
gloabls.h如下:
#ifndef _GLOBALS_H #define _GLOBALS_H //-------------------------------------------------------------------- // Include Files #include "lrun.h" #include "web_api.h" #include "lrw_custom_body.h" //-------------------------------------------------------------------- // Global Variables #endif // _GLOBALS_H
#include,#ifndef这些都是预处理。
所谓预处理是指对一个源程序进行编译时,系统将首先自动引用预处理程序对源程序中的预处理部分进行处理,处理完毕后再自动进入源程序的编译。
预处理是C语言的重要功能,define宏定义也是预处理。
Include是把指定的文件与当前源文件连成一个文件。
Ifndef,define和endif是为了防止头文件被重复调用。
18.变量位置决定变量使用范围:
1.局部变量
例如再某个action中的某个函数中定义一个变量,则只能在该函数中引用,如下的变量i,sum等:
switchaction() { int i=1,sum=0; int count; do{ sum = sum+i; i++; }while(i<=10); lr_output_message("1到10之间和为:%d",sum); return 0; }
2.全局变量,但是只能在定义此变量之后的使用,在此变量之前,不能使用,如下的变量ddaccountcsrfmiddlewaretoken,x等:
add_account() { lr_think_time(15); web_reg_save_param("addaccountcsrfmiddlewaretoken","LB='csrfmiddlewaretoken' value='","RB=' />",LAST); int x=0; web_url("add", "URL=http://192.168.1.102:8000/users/userprofile/add/", "Resource=0", "RecContentType=text/html", "Referer=http://192.168.1.102:8000/users/userprofile/", "Snapshot=t11.inf", "Mode=HTML", EXTRARES, "Url=/static/xadmin/vendor/font-awesome/fonts/fontawesome-webfont.eot?", ENDITEM, LAST); return 0; }
3.全局变量,在整个Action代码中都可以使用,如下x变量(变量必须是放在gloabls.h文件中):
gloabls.h文件内容:
#ifndef _GLOBALS_H #define _GLOBALS_H //-------------------------------------------------------------------- // Include Files #include "lrun.h" #include "web_api.h" #include "lrw_custom_body.h" int x=0; //-------------------------------------------------------------------- // Global Variables #endif // _GLOBALS_H
19.全局变量与局部变量
局部变量
局部变量也称为内部变量,它是在函数内定义的,其作用域仅限于函数内部,离开该函数后不可以使用。虚拟用户脚本中的局部变量应该定义在vuser_init(),action(),vuser_end(),新创建的用户action及用户自定义函数的内部。
全局变量
全局变量也称为外部变量,它是在函数外部定义的变量,在定义位置后的所有脚本中都可以调用。虚拟用户脚本中的全局变量应该定义在vuser_init(),action(),vuser_end(),新创建的用户action及用户自定义函数的外部。
演示实例
在头文件globals.h中定义一全局变量 int sum =10;然后在vuser_init,Action,vuser_end三个函数中加入语句
lr_output_message("sum2 = %d", sum);正常运行
如果只在Action中定义int sum =10,而vuser_init与vuser_end没定义,运行时就会报错
20.脚本的调试
脚本的提示对于脚本的编写非常重要
断点设置技术时脚本开发中最重要的开发技术
当预期结果与实际结果不一致时,可以在怀疑有问题的代码前插入断点,当程序运行到断点的时候,就会停下来,这时候可以通过日志,定位问题。
设置断点的四种方式
点击右键选Toggle Breakpoint
或者点击菜单栏的insert->Toggle Breakpoint
或者按F9设置断点
或者在代码行,左击添加或撤去断点
单步跟踪
每执行一条语句,程序就会听下来,可以结合日志分析脚本
方法:
按F10
或者运行 run step by step按钮
或者 Replay->Run Step by Step
Bookmarks设置标签
按ctrl+F2可以在代码行上设置一个标签,通过按F2与shift+F2,可以往前往后切换代码行。
代码折叠
录制出来的代码比较长,可以设置折叠,方便查看,鼠标右键,找到菜单expand/collapse,可以设置脚本为折叠模式。
代码日志定位
如果需要找到代码所对应的日志位置,可以在函数上单击右键,选Go to Step in Replay log 命令
快速打开代码目录
单击右键,选open script directory 命令就可以打开代码所在的目录
21.脚本模板使用
如何使用模板
性能测试脚本如果很多,要规范脚本,就需要模板功能。
先创建一个空脚本,在脚本中说明维护信息,保存为模板,然后打开file下的“保存为模板”(File->User-Defined Template->Export to Template...),以后每次开发的时候,就可以使用模板的形式,统一规范某些内容。
22.脚本的导入与导出
VuGen的脚本有很多文件组成,运行后还会产生日志文件与测试结果,要管理好这些,可以通过打包的方式保存以便管理与使用:
File->Manage Zip Files->Export to zip
Runtime files(运行时文件):只包含运行脚本的基本内容,比较小
All files(所有文件):整个脚本目录,包括日志与运行结果,比较大
23.在脚本中加载dll函数
Loadrunner提供了加载DLL的函数
lr_load_dll(char*library_name).通过在参数中给出dll文件的地址,可以将已经用visucalc++开发好的DLL文件加载到loadrunner的执行空间中.dll加载成功之后,可以调用dll中定义的任何导出函数,而无须在脚本中对其进行声明。
例如: Lr_load_dll("my_dll");
Myfunc();//本函数在my.dll中定义,在加载my.dll后,可以立即调用。
Lr_load_dll函数主要用在基于C语言解释器的虚拟用户中。
在函数的参数中可以指定调用Dll的完整路径,也可以只提供其文件名,脚本将会按照系统的默认路径来查找Dll。
在windows平台下如果不指定路径,则按照visualc++的loadlibrary函数的查找对应的Dll文件。
24.Vuser常用函数
lr_end_sub_transaction: 标记子事务的结束以便进行性能分析
lr_end_transaction_instance:标记事务实例的结束以便进行性能分析
lr_fail_trans_with_error:将打开事务的状态设置为LR_FAIL并发送错误消息
lr_get_trans_instance_duration:获取事务实例的持续时间(由它的句柄指定)
lr_get_trans_instance_wasted_time:获取事务实例浪费的时间(由它的句柄指定)
lr_get_transaction_duration:获取事务的持续时间(按事务的名称)
Lr_get_transaction_think_time:获取事务的思考时间(按事务的名称)
Lr_get_transaction_wasted_time:获取事务的浪费时间(按事务的名称)
Lr_save_string()函数用于把一个字符串保存到参数中。
函数语法结果如下:
Int Lr_save_string(const char *param_value,const char *param_name)
param_value:是将要保存的字符串,
char *param_name:是将要保存的参数名称,
例如:
Lr_save_string("abcdefg","param");
执行后,将把字符“abcdefg”保存到param中,然后脚本就可以直接通过{param}来使用参数param
Lr_save_var用来把字符串中的一部分内容保存为参数,函数语法如下
Lr_save_var(const char *param_value,unsigned long const value_len,unsigned long const option,const char*param_name);
param_value:是将要进行截取的字符串
value_len:是将要截取的长度
option:是留参数,可设为0
param_name:是保存的参数名称
例如:
lr_save_var("abcdefg",5,0,"paramstr");
执行后,将把字符串“abcdefg”中前5个,即“abcde”保存到参数paramstr,然后脚本中就可以直接通过{paramstr}来使用参数paramstr
Lr_eval_string函数的使用非常广泛,主要是用来返回参数中的实际内容,也可以返回一个包含参数的字符串的实际内容,语法结构如下:
Char *lr_eval_string(const char*instring);
instring:是参数或包含参数的字符串
例如:
lr_save_string("abcdefgh","paramstr");
Lr_output_message("paramstr=%s",lr_eval_string("{paramstr}"));
执行以上两语句后,将输出“paramstr=abcdefgh”
25.
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构