一、数据库性能测试
脚本说明
1. 数据操作脚本准备 Testdb.java
import java.sql.*;
import java.text.SimpleDateFormat;
public class Testdb {
publicstatic void main(String[] args) {
// 如果传入的参数不等于2,则给出提示信息"调用:java test_db ip:port recordcnt"
if (args.length != 2) {
System.out.println("调用:java test_db ip:portrecordcnt");
return;
}
// 根据传入的参数,动态建立连接URL
String url ="jdbc:oracle:thin:@"+args[0];
int cnt = Integer.parseInt(args[1]);
// 1 Java 连接 Oralce
try {
//数据库连接初始化操作
Class.forName("oracle.jdbc.driver.OracleDriver").newInstance();
Connectionconn = DriverManager.getConnection(url, "test",
"administrator");
//声明起初记录插入时间
longtimeBegin;
java.util.Dated1 = new java.util.Date();
//循环插入记录
PreparedStatementpstmt = conn
.prepareStatement("insertinto test_db(ID,time) values (?,?)");
Statements = conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,
ResultSet.CONCUR_READ_ONLY);
timeBegin= d1.getTime();
SimpleDateFormatdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
for(int i = 1; i <= cnt; i++) {
pstmt.setInt(1, i);
pstmt.setString(2, df.format(newjava.util.Date()));
pstmt.executeUpdate();
}
s.close();
conn.close();
//诸末尾记录跟初始记录的时间差
java.util.Dated2 = new java.util.Date();
System.out.println("用时 : " + (d2.getTime() - timeBegin) + " 毫秒");
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
System.out.println("找不到ORALCE数据驱动");
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
}
2. 批处理文件建立 test.bat
@ echo off
if "%JAVA_HOME%" =="" goto error_setting
set CLASSPATH=ojdbc14.jar;Testdb.jar
rem 当前路径 dir "%~dp0"
java -classpath %CLASSPATH% Testdb %1 %2
goto end
:error_setting
echo JDK环境变量未正确设置
goto end
:end
3. 编写LR脚本。
Action()
{
//调用windows可执行程序
system("testdb127.0.0.1:1521:orcl 1000");
return0;
}
注意:
Ø 几个脚本并发,集合一定要设置成相同的名称;
Ø Java程序所依赖的jar包以及批处理文件应放置到脚本所在目录。
二、FTP测试
脚本演示
ftp_logon_ex();
ftp_get_ex();
ftp_put_ex();
三、文件下载
脚本演示
web_set_max_html_param_len();
web_get_int_property();
Fwrite();
四、http接口测试
脚本演示web_url() web_submit_data()
1. web_custom_request()函数介绍
语法:
Int web_custom_request (const char *RequestName, <List of Attributes>,
[EXTRARES, <List of Resource Attributes>,] LAST );
返回值
返回LR_PASS(0)代表成功,LR_FAIL(1)代表失败。
参数:
RequestName:步骤的名称,VuGen中树形视图中显示的名称。
List of Attribute:支持的属性有以下几种:
1. URL:页面地址。
2. Method :页面的提交方式,POST或GET。
3. TargetFrame:包含当前链接或资源的frame的名称。参见List of Attributes的同名参数。
4. EncType:编码类型。
5. RecContentType:响应头的内容类型。参见List of Attributes的同名参数。
6. Referer:参见List of Attributes的同名参数。
7. Body:请求体。参见List of Attributes的同名参数。
8. RAW BODY:参见List of Attributes的同名参数。
9. BodyFilePath:作为请求体传送的文件的路径。它不能与下面的属性一起使用:Body,或者其他Body属性或Raw Body属性包括BodyBinary,BodyUnicode, RAW_BODY_START或Binary=1。
10. Resource、ResourceByteLimit、Snapshot、Mode:参见List of Attributes的同名参数。
11. ExtraResBaseDir:参见List of Attributes的同名参数。
12. UserAgent:用户代理,它是一个HTTP头的名字,用来标识应用程序,通常是浏览器,它呈现的是用户和服务器的交互。
例如:头信息“User-Agent:Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)”识别的是Window NT下的IE浏览器6.0。其他的User-Agent的值用来描述其他的浏览器,或者非浏览器程序。通常,一个应用程序中所有的请求都使用相同的用户代 理,录制者作为一个运行时参数来指定(Run-Time Setting—BrowserEmulation—User Agent)。不管怎么说,即使是在一个简单的浏览器进程中,仍有可能会用到直接与服务器交互的非浏览器组件(例如ActiveX控件),通常他们有着不 同于浏览器的用户代理属性。指定“UserAgent”表示这是一个非浏览器的请求。指定的字符串被HTTP头“User-Agent:” 使用,在某些情况下,它同时会影响回放脚本时的行为。例如,不使用浏览器缓存,假设指定的URL属于资源等等。
LoadRunner本身不检查指定的字符串与浏览器本身的值是否相同。
13. Binary:“Binary=1”表示页面请求体中的每一个以file://x/##形式出现的值(在这里“##”代表2个十六进制数字),都会被替换为单字节的十六进制的值。
如果“Binary=0”(默认值),所有的字符序列只是按照字面的值传递。
需要注意双斜杠的用法。在C编译器中双斜杠被解释为单斜杠。如果不需要零字节,单斜杠可以在Binary不等于1的情况下使用(例如,使用\x20代替file://x20/)。如果需要零字节,那么只能使用file://x00/且设置 “Binary=1”,\x00在逻辑上会被截断。
14. ContentEncoding
指定请求体的使用指定的方式(gzip或者deflate)进行编码(例如,压缩),相应的“Content-Encoding:”HTTP头会和此请求一起发送。这个参数适用于web_custom_request和web_submit_data。
EXTRARES:表明下面的参数将会是List Of ResourceAttributes了。
LAST :结尾的标示符。
2. 脚本中错误处理
void lr_continue_on_error ( intvalue );
常量名称 常量值 含义
LR_ON_ERROR_NO_OPTIONS 0 取消出错继续执行设置
LR_ON_ERROR_CONTINUE 1 发生错误继续运行脚本
LR_ON_ERROR_SKIP_TO_NEXT_ACTION 2 发生错误跳至下个Action运行
LR_ON_ERROR_SKIP_TO_NEXT_ITERATION 3 发生错误跳至下一迭代来运行
LR_ON_ERROR_END_VUSER 4 发生错误结束当前用户
lr_continue_on_error调用后将对其后面所有的语句产生影响。因此,脚本中较常用的是lr_continue_on_error (0)与lr_continue_on_error (1)。这两个语句成对出现,期间包含着需要设置为发生错误停止执行的关键业务脚本。
3. 参数与变量使用
int lr_save_string( const char*param_value, const char *param_name);
变量转换为参数。
char *lr_eval_string( const char *instring);
获取参数。
Strcpy(char * ,char *);
参数转换为变量。
4. 乱码处理
int lr_convert_string_encoding( const char*sourceString, const char *fromEncoding, const char *toEncoding, const char*paramName);
lr_convert_string_encoding("登陆成功",NULL,"UTF-8","temp");
如果这样用得出的结果是
登录æˆåŠŸ\x00
而正确的结果应该是
登录æˆåŠŸ
为了去掉这个最后的\x00,可以通过下面这个办法去掉
lr_save_string(lr_eval_string("{temp}"),"temp");
当你对一个带有/x00的参数取值时,会自动去除掉,所以只需要再存一次就行了.
五、SOCKET协议脚本录制
主要函数:
int lrs_create_socket( char*s_desc, char *type, [ char* LocalHost,] [char* peer,] [char *backlog,] LrsLastArg);
s_desc:要初始化的套接字标识符;
Type:套接字类型,TCP/UDP;
LocalHost:绑定本地端口;
Peer:远程机器端口;
Backlog:请求连接队列的长度,如backlog=25;
LrsLastArg:参数结束标识符。
int lrs_send( char *s_desc,char *buf_desc, [char *target], [char *flags,] LrsLastArg );
int lrs_receive( char*s_desc, char *bufindex, [char *flags], LrsLastArg );
lrs_receive()默认超时时间为10S,通过lrs_set_recv_timeout()和lrs_set_recv_timeout2()制定超时时间。
参数化:
action:
paraData=<NewParam>;
rs_save_param_ex("socket0","user",lr_eval_string(paraData),0,strlen(lr_eval_string(paraData)),NULL,"data_param");
//把测试用参数通过函数,传递给 “data_param”,把data_param参数放在Data.ws
data.ws
send buf0 "<data_param>"
六、调用JAR包
脚本演示
七、调用DLL动态库
脚本演示
第一种:
lr_load_dll("LRDllTest.dll");菜单“File-Add file to script”,把要引用的DLL加进来,Agent的Enable Firewall Agent选项不要勾上。
第二种:mdrv.dat方法
将LRDllTest.dll拷贝到LoadRunner安装路径的Bin目录下。
修改mdrv.dat文件(安装路径的dat目录下),因为选择的是默认的Web协议,所以找到[lrun_api]节点,在后面加上一句: WINNT_DLLS=LRDllTest.dll
八、关联操作
脚本演示
1. 方法一:自动关联
1.Tools-Recording Options。
2.设置完成后录制登陆 - 退出过程。
3.利用LR自带的自动关联进行关联。
2. 方法二:手动关联
1:录制测试脚本,录制二遍
2:使用WinDiff工具找出两次脚本的不同,判断是否需要进行关联(Tools下的 Compare with Vuser进行2个相同操作的脚本对比)
3:确定插入关联的位置
4:在VIEW TREE中使用web_reg_save_param函数手动建立关联
5:将脚本中有用到关联的数据,用参数代替
6:验证关联的正确性
函数原型:
int web_reg_save_param (const char*ParamName, <List of Attributes>, LAST);
参数说明:
ParamNam:存放动态数据的参数名称
List of Attributes:其它属性,包含Notfound、LB、RB、RelFrameID、Search、ORD、SaveOffset、Convert、SaveLen。
● Notfound:指当找不到要找的动态数据时,怎么处理。
● Notfound=error,当找不到动态数据时,发出一个错误信息,为LoadRunner的默认值。
● Notfound=warning,当找不到动态数据时,不发出错误信息,只发出警告,脚本会继续执行下去不会中断。
● LB:动态数据的左边界字符串,该参数为必选参数,并区分大小写。
● RB:动态数据的右边界字符串,该参数为必选参数,并区分大小写。
● ORD:指提取第几次出现的左边界的数据,该参数为可选参数,默认值是1。假如值为All,则查找所有符合条件的数据并把这些数据存储在数组中。
● Search:搜寻的范围。可以是Headers(只搜寻Headers)、Body(只搜寻Body部分,不搜寻Headers)、 Noresources(只搜寻Body部分,不搜寻Header与Resource)或是All(搜寻全部范围,此为默认值),该参数为可选参数。
● RelFrameID:相对于URL而言,欲搜寻的网页的Frame,此属性可以是All或是具体的数字,该参数为可选参数。
● SaveOffset:当找到符合的动态数据时,从第几个字符开始才存储到参数中,该参数为可选参数,此属性值不可为负数,其默认值是0.
● Convert:可能的值有两种:
● HTML_TO_URL:将HTML-encoded数据转成URL-encoded数据格式。
● HTML_TO_TEXT:将HTML-encoded数据转成纯文字数据格式。
● SaveLen:从Offset开始算起,到指定长度内的字符串,才储存到参数中,该参数为可选参数,默认值为-1,表示储存到结尾整个字符串。
例子:web_reg_save_param("Test","LB=userSessionValue","LB=>","Ord=1"
"RelFrameID=1.21","Serch=Body","IgoreRedirections=Yes",LAST);
九、LR脚本编写规范
规范说明及模板演示
1.一般约定
1.1具体脚本规则,必须在具体代码中加注释,以便脚本开发人员阅读和理解脚本。
1.2脚本的存放规则:
测试脚本应该存储在指定的库中,例如一个共享的驱动盘或测试管理工具中。为节省空间,便于复用,测试脚本的文件夹下的: result,res,date 文件夹,后缀名为:.idx .log .txt 文件都可不必保留。
1.3脚本中 action的命名规则:
录制脚本前有个命名规则非常有必要,否则同一动作会有多个事务,会给数据收集、分析带来不必要的麻烦。
假设某J2EE系统实现开户、销户业务,那么自然会有Login、OpenAccount、DestroyAccount和LoginOut动作。那么录制LR脚本时,脚本中的Action列表应该为:
脚本1:初始化-Login-OpenAccount-LoginOut-结束动作
脚本2:初始化-Login-DestoryAccount-LoginOut-结束动作
(即只有一个动作不同)这样做其目的是创建场景Scene时,在Login、LoginOut的事务只被记录一次
1.4 变量命名规则
变量的命名的基本原则是使得变量的含义能够从名字中直接理解。可以用多个英文单词拼写而成,每个英文单词的首字母要大写,其中英文单词有缩写的可用缩写;变量的前缀表示该变量的类型;对于作用域跨越10行以上的变量名称不能少于4个字符,除循环变量,累加变量外不得使用I、j、k等名称的变量。变量分为取全局变量和局部变量,对于全局变量以加前缀“g_”来区分。
1.5 常数名规则
常量所有的字母均为大写。并且单词之间使用下划线”_”隔开。例如:
USER_LIST_MAX
NEW_LINE
1.6 函数名命名规则
函数/过程名称应该尽量使用能够表达函数功能的英文名称,函数名称中应该禁止使用如同function1,function2等含义不清的名称。单词间应该使用大小写分隔。全局函数/过程名称以“g_”前缀开始。
2. 代码注释约定
在软件中对每个文件头,自定义函数和变量,重要的处理过程都要有必要的注释。
2.1 源程序头的注释和规范
每个文件头插入注释,标明文件的用途和作者,注释如下:(注释尽量用中文)
//程序名称
//版权说明
//版本号:
//功能:
//开发人:
//开发时间:
//修改者:
//修改时间
//修改简要说明
//其他
2.2 函数的注释
每个函数前面注明函数的功能和输入,输出。注释为:
//名称
//功能:(说明函数的功能)
//输入参数:(说明每个输入参数的用途和取值约定)
//输出参数:(说明每个输出参数的用途和取值约定)
//返回:(说明返回值,返回值的含义和约定)
2.3 变量注释
直接在变量后面注明变量的用途和取值约定,如:
int status; //记录处理状态,0: 成功,1: 错误
2.4 类型定义注释
指类和记录等等定义的注释。在注释中标明定义的用途。
2.5 区的注释
同一个类的成员方法要求排列在一起,共同协作而实现同一个功能的函数和过程要求排列在一起。代码通常使用几个函数和过程来实现某一项功能,这时候需要使用区注释将这些具有共同目的的函数和过程标明出来。
使用整行的”*”作为隔离行,让程序清晰可读。
一般删除的代码不建议直接删除,最好用“//”注释起来。
2.6 代码中的注释
在代码中要求注释的地方有:
代码中的关键部分;
在使用特殊算法或者逻辑性较强的代码;
在修改或删除代码部分,需要加注释;修改/删除人,目的.
3. 格式化代码
程序应采用缩进风格编写,每层缩进使用一个制表位(TAB),类定义、方法都应顶格书写;
左花括号要另起一行,不能跟在上一行的行末;
一个变量定义占一行,一个语句占一行;
对独立的程序块之间、变量说明之后必须加空行;
对于较长的语句(>80字符)要分成多行书写,长表达式要在低优先级操作符处划分新行,操作符放在新行之首,划分出的新行要进行适当的缩进,使排版整齐,语句可读;
循环、判断等语句中若有较长的表达式或语句,则要进行适应的划分;
在结构成员赋值等情况,等号对齐,最少留一个空格;
若函数或过程中的参数较长,则要进行适当的划分。
形参的排序风格:
Ø 最常使用的参数放在第一位;
Ø 输入参数列表应放在输出参数列表的左边;
Ø 将通用的参数放在特殊的参数的左边