LoadRunner,是一种预测系统行为和性能的负载测试工具。通过模拟上千万用户实施并发负载及实时性能监测的方式来确认和查找问题,LoadRunner能够对整个企业架构进行测试。企业使用LoadRunner能最大限度地缩短测试时间,优化性能和加速应用系统的发布周期。
LoadRunner可适用于各种体系架构的自动负载测试,能预测系统行为并评估系统性能。

LoadRunner 更多的了解可以查看百度百科,我觉得上面讲的很全面了。
本篇文章是我近段时间使用 LoadRunner 对系统进行性能测试而写,因为时间有限,所能了解的东西也有限,所以能写的也就一点点,不多…

新建脚本

新建脚本,一般来说,应该都是使用的 LoadRunner 程序的脚本录制功能,这个功能是可以自动生成脚本文件的,然后我们再改改应该就可以了。
但是我这边有一些情况比较特殊,不能使用录制功能,所以只能是纯手写咯。
既然是要写脚本,打开程序的操作肯定是必要的吧:LoadRunner应用程序->创建/编辑脚本->新建/打开脚本

  1. 创建/编辑脚本
    创建/编辑脚本

  2. 新建/打开脚本
    新建/打开脚本

  3. 脚本类型(如果是新建脚本)–默认就行
     脚本类型

  4. 选择取消即为不录制
    选择取消即为不录制

函数

接下来我们介绍一下使用了哪一些函数,函数简单,但是还是要记一下,以为要用的东西嘛,不记得就尴尬了…

函数列表

这里列出我使用到的所有函数,都是 C 语言的函数哦:

1
2
3
4
5
6
7
8
9
10
11
12
int web_add_auto_header( const char *Header, const char *Content );   
int web_set_max_html_param_len( const char *length );
int web_reg_save_param_ex( const char *ParamName, [const char *LB, ][const char *RB,] <List of Attributes>, <SEARCH FILTERS>,LAST );
int web_reg_find( const char *attribute_list, LAST );
int lr_start_transaction( const char *transaction_name );
int web_custom_request( const char *RequestName, <List of Attributes>, [EXTRARES, <List of Resource Attributes>,] LAST );
char *lr_eval_string( const char *instring );
int atoi( const char *string );
int lr_output_message( const char *format, exp1, exp2,...expn.);
int lr_end_transaction( const char *transaction_name, int status ) ;
void lr_think_time( double thinkTime);
int lr_message( const char *format, exp1, exp2,...expn.);

函数介绍

上面就是使用到的简单的函数,下边来对他们一一介绍,建议看官方文档咯,在程序里边的帮助就有相应的文档可以查.

  1. web_add_auto_header: Adds the specified header to all subsequent HTTP requests
    参数:
  • Header: 请求头的参数,eg: Accept
  • Content: 就是请求头参数对应的值咯,eg:如果参数是 Accept,那么值我们可以设置为:application/json
    就是设置 HTTP 的请求头,并将这个请求头应用到后续的请求中去–即设置一次,后续无忧。eg:web_add_auto_header(“Accept”, “application/json”);

2.web_set_max_html_param_len: Sets the maximum length of any HTML string that can be retrieved and saved as a parameter
参数:

  • length: 长度为字符形式,默认是 256 个字符
    就是可以检索和保存为参数的任何 HTML 字符串的最大长度。一般地,如果没用使用 HTML 请求的响应值最为参数传递给下一个 HTML 请求,那么就没必要设置这个值。

3.web_reg_save_param_ex: Registers a request to save dynamic data information to a parameter
参数:

  • ParamName: 定义参数名称
  • LB: 动态数据边界,左边界
  • RB: 动态数据边界,右边界
  • Attributes:
    • DFES: 在执行所需的搜索操作之前使用的数据格式扩展的逗号分隔列表。可选的。
    • NOTFOUND: 在没有找到搜索项并生成空字符串时的处理选项。根据函数的不同,搜索项可以是边界,也可以是XPath。可选的。
      “Notfound=error”是默认值,当没有找到搜索项时,会引发错误。
      “Notfound=warning”不发出错误。如果没有找到搜索项,则将参数count设置为0,并继续执行脚本。如果您希望查看是否找到了字符串,但又不希望脚本失败,那么“警告”选项是最理想的。
      注意:如果脚本启用了Continue on Error,那么即使NOTFOUND被设置为“Error”,当搜索项没有找到时,脚本也会继续执行,但是会向扩展日志文件写入一条错误消息。
      可选的。
    • Ordinal: 表示匹配的序号位置或实例。除了传递一个数字外,还可以指定LAST。如果您指定所有参数,则参数值将保存在数组中。可选的。默认实例是1。
      此属性不适用于web_reg_save_param_xpath。
    • SaveLen:找到的值的子字符串长度,从指定的偏移量保存到参数。
      可选的。默认值是-1,表示保存到字符串的末尾。
      此属性不适用于web_reg_save_param_xpath。
    • SaveOffset:将找到的值的子字符串的偏移量保存到参数。偏移量必须是非负的。
      此属性不适用于web_reg_save_param_xpath。
      可选的。默认值是0。
    • SelectAll:指定是否保存所有找到的匹配项。如果指定了Yes,它将把匹配的值保存在数组中。可选的。默认值是No。
      此属性不适用于web_reg_save_param_ex。
  • SEARCH FILTERS: 指定缓冲区内搜索字符串的部分
    • 使用:
      SEARCH_FILTERS,
      “RelFrameID=ALL”,
      “IgnoreRedirections=off”,
      “Scope=Body”,
      “ContentType=text/html”,
      “RequestUrl=http://mansfied/cgi-bin/echo.asp",
    • 说明:
      • ContentType:只搜索具有指定ContentType标头的响应。ContentType可以包含*通配符。
      • HeaderNames: HTTP响应头名的逗号分隔列表。只搜索指定头的值。此参数仅适用于范围为“标头”的情况。
      • IgnoreRedirections:如果“IgnoreRedirections=Yes”,服务器响应是重定向信息(HTTP状态码300-303,307),响应不搜索。相反,在接收到重定向响应之后,GET请求被发送到重定向的位置,并在该位置的响应上执行搜索。默认是No。
      • RelFrameID: HTML页面相对于请求URL的层次结构。可能的值是ALL或一个数字。单击RelFrameID属性查看详细描述。
        注意:在GUI级脚本中不支持RelFrameID。
      • RequestURL:只搜索对该请求的响应。URL可以包含*通配符。
        范围:在何处搜索分隔的数据。可选的。可能的值是全部-搜索整个缓冲区、 只搜索标题、只搜索身体数据、只在Cookies中搜索;
        如果没有指定DFES参数,则可以使用All。如果使用Scope=Headers和HeaderNames过滤器,则只搜索指定header的值。如果没有使用HeaderNames过滤器,则搜索所有标题文本。
      • Scope=所有不应用于web_reg_save_param_xpath。默认值是All,除了web_reg_save_param_xpath,它的默认值是Body。
        就是 2 所讲,所有请求中的响应值缓存区,按照设置,将数据保存在定义的参数中,再将这个参数作为全局参数,供后续请求使用。
  1. web_reg_find: Registers a search for a text string on an HTML page
    参数:
  • attribute_list:参数列表,有好多的参数,这里先讲两个
    • Text: 在搜索的文本中搜索指定的内容
    • SaveCount: 当搜索匹配到 Text 指定的内容是,SaveCount 就会计数
      就是在 HTML 页面上注册对文本字串的搜索,只对靠近它的一个请求有用(自测发现)
  1. lr_start_transaction: Marks the beginning of a transaction
    参数:
  • transaction_name: 即事务名称
    就是注册事务开启
  1. web_custom_request: Allows you to create a custom HTTP request with any method supported by HTTP
    参数:
  • ReuqestName: 注册请求的名称
  • Attributes:
    • URL: 访问的请求
    • Method: HTTP 请求的方法 GET、POST等
    • EncType: 请求头中的 Content-Type
    • Resource: 只是 URL 是否为一个资源,“1” 表示是一个资源,不会影响脚本的运行,遇到错误报“警告”;“0” 表示 URL 是关键的,不受 RTS 的影响。
    • Referer: 引用/参照页面
    • Snapshot: 快照文件
    • Mode: 记录级别为 HTML 或 HTTP
    • Body: 请求使用的参数
  • LAST: 表示列表字段的结束
    用于发送 HTTP 请求的函数
  1. lr_eval_string:Returns the string argument after evaluating embedded parameters(将 web_ref_find 计算后的参数转为一个字符串)
  2. atoi: Converts a string to an integer value(将字符串转换为整型)
  3. lr_output_message: Sends a message to log files, output windows, and other test report summaries(发送信息到日志文件、输出窗口和其他测试报告摘要)
  4. lr_end_transaction: 事务结束
    参数:
  • transactions_name: 事务名称
  • status: LR_PASS、LR_FAIL、LR_AUTO、LR_STOP
  1. lr_think_time: 记录的思考时间,为字符串形式 eg: lr_think_time(“2”);为思考时间2s
  2. lr_message: Sends a message to log files and output windows

简单脚本编写

此脚本是针对自己写的一个小服务 Demo 经行测试的,所以可能会有一些不合理的地方。

服务 Demo(JAVA)

使用的是 SpringBoot 创建的一个小实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
@SpringBootApplication
@EnableTransactionManagement
@RestController
@RequestMapping(value = "/Demo")
public class DemoApplication {

public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}

@PostMapping(value = "/userInfo",produces = "application/json;charset=UTF-8", consumes = "application/json;charset=UTF-8")
public UserInfo test(@RequestHeader(value = "appName")String appName){
UserInfo userInfo = new UserInfo();
userInfo.setUserName("feigntest");
userInfo.setPassword("password");
return userInfo;
}

@PostMapping(value = "/getUserAge"/*,produces = "application/json;charset=UTF-8", consumes = "application/json;charset=UTF-8"*/)
public UserInfo getUserAge(@RequestParam (name = "userName")String userName){
UserInfo userInfo = new UserInfo();
userInfo.setUserName(userName);
userInfo.setPassword("password");
userInfo.setAge(22);
return userInfo;
}

}

脚本代码

此脚本包含目前在项目压测中使用的函数,每一个函数都有解释响应的理解,当然可能会有一些出入,主要是根据实际情况而定。(应该很详细了吧)
脚本里边包含:

  1. 设置思考时间
  2. 定义全局应用的请求头
  3. 取请求返回的数据作为参数进行传递
  4. 发送请求的一些设置
  5. 如何判断请求是否为正确返回
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    Action()
    {
    //Demo
    lr_think_time(1);
    web_add_auto_header("appName", "abc");//全局应用请求头--这里的请求头数据不做要求(乱写的),但是头的参数要存在,因为服务定义了

    //设置可以检索和保存为参数的任何 HTML 字符串的最大长度
    web_set_max_html_param_len("2048");

    //定义赋值参数,只能是全局的,不能定义局部,要不然编译不通过
    web_reg_save_param_ex(
    "ParamName=userName",//定义参数名称
    "LB/IC=\"userName\":\"",//LB:定义左边匹配符 IC:忽略大小写
    "RB=\",",//定义右边匹配符
    "Ordinal=1",//1:匹配的第一个数据, ALL:将所有匹配值保存为一个数组
    "SaveLen=-1",//不限定参数值的长度
    SEARCH_FILTERS,
    "Scope=Body",//搜索范围
    "RequestURL=*/Demo/userInfo*",//搜索指定的请求的响应值,如果使用完整的url作为指定请求,值为对应的web_custom_request的url的值,如果有时间戳,记得把时间戳也算上,否则会匹配不上,也可以使用通配符'*'
    LAST);

    //事务开启
    lr_start_transaction("userInfo");
    //定义可以判断请求成功的验证
    //函数注册一个请求,以搜索下一个操作函数(如web_url)检索到的Web页面上的文本字符串。
    web_reg_find("Text=\"userName\":\"feigntest\"", "SaveCount=userInfo_count",LAST);//计算看这个事务返回的数据,判断时候存在"userName": "feigntest"这个值,存在则userInfo_count计数+1
    //请求
    web_custom_request("userInfo",//请求名称--自定义即可
    "URL=http://10.37.1.185:8991/Demo/userInfo?time=1543200057562", //访问url
    "Method=POST", //HTTP Method
    "EncType=application/json",//即 指定处理请求的提交内容类型(Content-Type),如果这个不一致,请求会报错 415
    "Resource=0",
    "RecContentType=application/json", //指定返回的内容类型,仅当request请求头中的(Accept)类型中包含该指定类型才返回
    "Referer=http://10.37.1.185:8991/",
    "Snapshot=t13.inf",
    "Mode=HTML",
    "Body=", //不需要参数
    LAST);
    //判断是否正确结束事务
    if( atoi(lr_eval_string("{userInfo_count}")) > 0) {
    lr_end_transaction("userInfo", LR_PASS);
    } else {
    lr_end_transaction("userInfo", LR_FAIL);
    }

    //事务开启
    lr_start_transaction("getUserAge");
    //定义可以判断请求成功的验证
    web_reg_find("Text=\"age\":22", "SaveCount=getUserAge_count",LAST);//计算看这个事务返回的数据,判断时候存在"userName": "feigntest"这个值,存在则userInfo_count计数+1
    //请求
    web_custom_request("getUserAge",//请求名称--自定义即可
    "URL=http://10.37.1.185:8991/Demo/getUserAge?time=1543200057562", //访问url
    "Method=POST", //HTTP Method
    //"EncType=application/json",//这个请求不能加 RequestHeader--ContentType,不然会让接口报400错误----如果一定要使用这个参数,那么我们的请求参数就不能放在Body定义,直接拼接到url中。。实际要根据接口定义来使用
    "Resource=0",
    "RecContentType=application/json", //指定返回的内容类型,仅当request请求头中的(Accept)类型中包含该指定类型才返回
    "Referer=http://10.37.1.185:8991/",
    "Snapshot=t13.inf",
    "Mode=HTML",
    "Body=userName={userName}", //使用上一个请求所得的参数值赋值使用,,也可以直接拼接到url上
    LAST);
    //判断是否正确结束事务
    if( atoi(lr_eval_string("{userInfo_count}")) > 0) {
    lr_end_transaction("getUserAge", LR_PASS);//正常返回状态为Pass
    } else {
    lr_end_transaction("getUserAge", LR_FAIL);//错误返回状态为Fail
    }

    return 0;
    }
测试结果的查看和日志选项

脚本编写完毕之后,要进行编译测试,确认脚本正常执行才能用于进行性能测试工作。接下来看看日志中如何确认脚本是否正常吧…

  1. 测试结果的查看(标准日志)

标准日志-默认

根据图片上的日志情况就可以反应出当前脚本的运行情况

  1. debug 调式
    正所谓“理想很丰满,显示很骨感”。并不是所有的脚本编写完成之后都能正常的运行,而根据 1 选项的日志却看不出来脚本的实际情况,那怎么办呢?认命?不存在的…
    可以先通过 debug 调式看看能不能找到问题…
    那么如何 debug 呢?
    这里要使用到两个按键 F5 和 F9,F5 就是运行啦,F9 就是 debug 断点设置和取消
    70% 的错误都是因为粗心大意而出现的,所以可以通过这种方式查看一下,是不是参数或者是语法导致的错误…

  2. 日志查看
    如果单纯的进行 debug 调式都不能解决问题,那就 只能通过高级日志的查看看看咯…
    它的位置如下图:
    高级日志

日志打印出来的就比标准日志要多得多,但是在性能测试阶段,建议使用 “仅在出错时返送消息” 或者 “始终发送消息–>标准日志” ,不然日志可能会将你的压力机磁盘写满,导致你后续无法继续工作。也建议偶尔自己去删除打印出来的日志,让压力机减负运行嘛。

参数设置

上边的例子没有用到参数列表,所以现在介绍参数列表的使用(例子根据上边的例子进行改造),所以下边开始对如何设置参数进行叙述。
这里进行简单的例子:
我们将上述例子中的语句稍微修改一下: web_add_auto_header("appName", "abc"); 修改为 web_add_auto_header("appName", "{appNameArg}"); ,此处的 ‘{appNameArg}’ 为我们定义的参数,中括号不能落下,否则就不是获取参数咯…
如果参数列表中没有定义 ‘appNameArg’ 这个参数,那么在脚本中的显示为绿色,如下图:
参数定义-1

这里要切记, 使用函数 ‘web_reg_save_param_ex’ 定义的参数,他就是绿色的哦,所以看到绿色参数时要确认是通过 ‘web_reg_save_param_ex’ 函数获取的,还是通过参数列表获取的,不要慌…

接下来看看如果使用参数列表:

  1. 打开参数列表定义工具
    参数定义-2

  2. 参数定义和选项介绍
    新建参数:点击“新建”,输入参数名称,回车即可
    参数类型:选择对应的参数名称设置参数类型,目前使用到的有 File、Random Number。File 即为文件,以.dat为后缀;Random Number 即为随机数。
    接下来展示两张图作为参考:
    参数定义-3

参数值的设置:
按编号:即为按列,其实列序号为 1 ,意思时这个参数它对应的时哪个列
按名称:即为列名
列分割符:Comma(逗号)、Tab(Tab空白)、Space(空格)
选择下一行与更新值时间搭配:
Sequential(连续的)、Random(随机的)、Unique(唯一的):
Each Iteration:迭代使用,执行一遍脚本用一个值,且当前进程内不会发生改变
Each occurrence:当前当次使用,执行一遍脚本,每次获取到的参数的值都是按顺序往下取值
Once:只使用一次,不重复利用
选择下一行(脚本关联–用于 File 参数):当创建了多个参数时,会发现在选择下一行这个下拉框内会出现一些数据为 Same line as 'arg' ,意思就是这个脚本中的同一个参数文件内的参数,行取值由 ‘arg’ 决定为哪一行(即为同一行的意思)。

参数定义-4

参数值的设置:
从 最小值-最大值 之前取值,即为从 1-100 之间随机取值

  1. 参数使用
    定义成功之后,函数 web_reg_save_param_ex 参数定义部分显示为粉红色,如图:
    参数定义-5

至此,LoadRunner 简单脚本的编写已经完成了,如遇有疑问或文章有问题,欢迎反馈…

参考文献

  1. 百度百科:https://baike.baidu.com/item/loadrunner/1926633?fr=aladdin
  2. LoadRunner-常用的函数:https://www.cnblogs.com/zhuzhubaoya/p/9084163.html

最后更新: 2019年11月25日 22:16

原始链接: https://maiyikai.github.io/2019/10/18/1571380748/

× ~谢谢大爷~
打赏二维码