一、前言:

本文适合初学者,包含很多细节,也作为自己的备忘。有不准确之处,欢迎指正。

二、准备:

1、以虚拟机中的Linux系统作为服务器,开启bugfree服务。

2、以fiddler作为抓包工具,辅助脚本开发。

3、脚本流程:bugfree登录--创建bug--解决bug。

三、实现过程:

3.1 脚本主体

创建空白脚本后,结构如下图,压力测试中一般我们将登录单独放在vuser_init中。这里为了整个流程更清晰,脚本全部写在Action中。

  

值得注意的是,我们设置脚本迭代次数,只对Action部分生效,而vuser_init和vuser_end只会运行一次。

  

开始写脚本前,我们对fiddler先进行一些过滤设置。

  

  在浏览器进行bugfree登录操作,fiddler抓取到结果,比较有用的信息是URL以及Headers项的请求类型(这里是POST)、参数列表。

  

  

  如果参数中以及后文的检查点文本中含有中文,需要设置loadrunner支持UTF-8编码格式,将含有UTF-8的项改为“Yes”:

  

  在已知请求类型为POST的前提下,执行Insert--new step--Submit Data。如果是GET请求,则需要插入Url函数。

  

  写入General信息:

  

  写入参数信息:

  

  点击确定后生成脚本。创建bug和解决bug与此类似,生成脚本如下:

 web_submit_data("创建缺陷",
"Action=http://192.168.232.132/bugfree/info/edit?type=bug&action=opened&product_id=1",
"Method=POST",
"TargetFrame=",
"Referer=",
"Mode=HTTP",
ITEMDATA,
"Name=BugInfoView[deleted_file_id]", "Value=", ENDITEM,
"Name=BugInfoView[lock_version]", "Value=", ENDITEM,
"Name=BugInfoView[product_id]", "Value=1", ENDITEM,
"Name=isPageDirty", "Value=1", ENDITEM,
"Name=templateTitle", "Value=", ENDITEM,
"Name=BugInfoView[title]", "Value=mutest20170927{title}", ENDITEM,
"Name=layer1_module", "Value=0", ENDITEM,
"Name=BugInfoView[productmodule_id]", "Value=0", ENDITEM,
"Name=BugInfoView[assign_to_name]", "Value=系统管理员", ENDITEM,
"Name=BugInfoView[mail_to]", "Value=", ENDITEM,
"Name=BugInfoView[severity]", "Value=1", ENDITEM,
"Name=BugInfoView[priority]", "Value=1", ENDITEM,
"Name=Custom[BugType]", "Value=代码错误", ENDITEM,
"Name=Custom[HowFound]", "Value=代码检查", ENDITEM,
"Name=Custom[BugOS]", "Value=Linux", ENDITEM,
"Name=Custom[BugBrowser]", "Value=Chrome", ENDITEM,
"Name=Custom[OpenedBuild]", "Value=Mu", ENDITEM,
"Name=Custom[ResolvedBuild]", "Value=", ENDITEM,
"Name=Custom[BugSubStatus]", "Value=", ENDITEM,
"Name=Custom[BugMachine]", "Value=", ENDITEM,
"Name=Custom[BugKeyword]", "Value=", ENDITEM,
"Name=BugInfoView[related_bug]", "Value=", ENDITEM,
"Name=BugInfoView[related_case]", "Value=", ENDITEM,
"Name=BugInfoView[related_result]", "Value=", ENDITEM,
"Name=attachment_file[]", "Value=", ENDITEM,
"Name=BugInfoView[action_note]", "Value=", ENDITEM,
"Name=BugInfoView[repeat_step]", "Value=<br />", ENDITEM,
LAST); web_submit_data("解决缺陷",
"Action=http://192.168.232.132/bugfree/bug/1/resolved",
"Method=POST",
"TargetFrame=",
"Referer=",
"Mode=HTTP",
ITEMDATA,
"Name=BugInfoView[deleted_file_id]", "Value=", ENDITEM,
"Name=BugInfoView[lock_version]", "Value=1", ENDITEM,
"Name=BugInfoView[product_id]", "Value=1", ENDITEM,
"Name=isPageDirty", "Value=1", ENDITEM,
"Name=templateTitle", "Value=", ENDITEM,
"Name=BugInfoView[title]", "Value=mutest20170927{title}", ENDITEM,
"Name=layer1_module", "Value=0", ENDITEM,
"Name=BugInfoView[productmodule_id]", "Value=0", ENDITEM,
"Name=BugInfoView[assign_to_name]", "Value=系统管理员", ENDITEM,
"Name=BugInfoView[mail_to]", "Value=", ENDITEM,
"Name=BugInfoView[severity]", "Value=1", ENDITEM,
"Name=BugInfoView[priority]", "Value=1", ENDITEM,
"Name=Custom[BugType]", "Value=代码错误", ENDITEM,
"Name=Custom[HowFound]", "Value=代码检查", ENDITEM,
"Name=Custom[BugOS]", "Value=全部", ENDITEM,
"Name=Custom[BugBrowser]", "Value=Chrome", ENDITEM,
"Name=Custom[OpenedBuild]", "Value=Mu", ENDITEM,
"Name=Custom[ResolvedBuild]", "Value=Mu", ENDITEM,
"Name=BugInfoView[solution]", "Value=By Design", ENDITEM,
"Name=BugInfoView[duplicate_id]", "Value=", ENDITEM,
"Name=Custom[BugSubStatus]", "Value=Hold", ENDITEM,
"Name=Custom[BugMachine]", "Value=", ENDITEM,
"Name=Custom[BugKeyword]", "Value=", ENDITEM,
"Name=BugInfoView[related_bug]", "Value=", ENDITEM,
"Name=BugInfoView[related_case]", "Value=", ENDITEM,
"Name=BugInfoView[related_result]", "Value=", ENDITEM,
"Name=attachment_file[]", "Value=", ENDITEM,
"Name=BugInfoView[action_note]", "Value=", ENDITEM,
"Name=BugInfoView[repeat_step]", "Value=<br />", ENDITEM,
LAST);

  至此,脚本主体完成。但这样的脚本很显然是不符合压测要求的:

  1、如果对登录单独压测,因为登录是查询型请求,与修改型请求不同,我们在数据库中无从校验其成功率。所以设置登录检查点函数是必要的。

  2、如果登录用户名不允许多IP同时登录,那么对用户名进行参数化是必要的。参数化的本质是应对数据库对参数值进行的唯一性校验。

  3、观察脚本,解决Bug步骤,其Bug ID是固定的,那么执行压测时,我们就一直在对同一个Bug进行解决缺陷操作,这显然是不合理的。我们需要将Bug ID和上一步创建Bug的Bug ID关联起来。这样,才能保证每次解决缺陷都是针对上一步刚刚创建的处于未解决状态的Bug。

  接下来,对脚本进行改进:

3.2 参数化

  参数化设置的目的是应对数据库对参数值的唯一性校验。其设置方式如下:

3.1.1 参数化设置

  打开Parameter List,点击左下角的【New】,创建新的参数。

  

  生成之后,右键选中待替换内容,选择【Use Existing Parameter】:

  

  或者,也可以直接选中待参数化内容,右键后选择【Replace with a Parameter】,一次性进行创建参数和替换。

3.2.2 Mysql数据库数据获取

  设置参数化之后,面临的问题就是大量数据从何而来。利用存储过程在数据库中创建大量数据,然后参数化文件读取这些数据,是个不错的方法。

  

  Next

  

  Next

  

  Next

  

  Next

  

  Next

  

  Next

  

  Next,写入sql语句

  

  数据已导入:

  

  参数类型即Parameter type还可选择其他类型,常用的如Date/Time,Rondom Nunmber(可用于注册型请求的用户名参数)等,遇到实际场景后补充。

3.3 检查点设置

  以登录为例,只要我们提交了请求,即使不能成功登录,服务器返回给我们的状态码依然是200,而loadrunner判断请求是否成功的依据就是返回的状态码,所以在未加检查点之前,我们无从判断登录业务是否成功。当然,非查询类请求,可以去数据库进行校验。

  因此我们需要加入检查点来进行业务是否真正成功的校验。检查点的思想是,在请求响应内容中,查找特殊字段,例如登录请求响应中的“欢迎”、“退出”等等字段。下面以Bug登录为例,进行检查点详细解析。

  首先,我们去分析登录请求中,检查点需要设置的文本内容。

HTTP/1.1  Found
Date: Sun, Dec :: GMT
Server: Apache/2.4. (Unix) OpenSSL/1.0.1f PHP/5.5. mod_perl/2.0.-dev Perl/v5.16.3
X-Powered-By: PHP/5.5.
Expires: Thu, Nov :: GMT
Cache-Control: no-store, no-cache, must-revalidate, post-check=, pre-check=
Pragma: no-cache
Set-Cookie: PHPSESSID=a3dta30c68sb9l7fc9t4ancp03; path=/
Set-Cookie: language=deleted; expires=Thu, -Jan- :: GMT; Max-Age=; path=/
Set-Cookie: language=bece46be16477e1ab82f9d40a53074cb0a54e105s%3A5%3A%22zh_cn%%3B; expires=Tue, -Jan- :: GMT; Max-Age=; path=/
Location: http://192.168.232.128/bugfree/index.php
Content-Length:
Keep-Alive: timeout=, max=
Connection: Keep-Alive
Content-Type: text/html

  在响应内容中,貌似没有特殊字段。只有“302”值得注意,这个状态码表示请求发生重定向,对象已临时移动。那么,也只有登录成功之后,才能进行跳转首页的重定向。为了验证该结论,我做一次失败登录。第二次失败登录与第一次成功登录相比,缺少了后续跳转首页等请求。

  

  再观察其响应内容,状态码是200。至此,我们可以选定登录检查点函数的检查文本为“302”。

HTTP/1.1 200 OK
Date: Sun, 10 Dec 2017 11:07:03 GMT
Server: Apache/2.4.7 (Unix) OpenSSL/1.0.1f PHP/5.5.9 mod_perl/2.0.8-dev Perl/v5.16.3
X-Powered-By: PHP/5.5.9
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache
Content-Length: 4039
Keep-Alive: timeout=5, max=100
Connection: Keep-Alive
Content-Type: text/html

  执行Insert--new step--web_reg_find,reg表示注册型函数,这类函数作用于其下文第一个函数。

  

  生成脚本如下:

web_reg_find("Fail=NotFound",
"Search=All",
"SaveCount=count",
"Text=302",
LAST); web_submit_data("login",
"Action=http://192.168.232.128/bugfree/index.php/site/login",
"Method=POST",
"TargetFrame=",
"Referer=",
"Mode=HTTP",
ITEMDATA,
"Name=LoginForm[username]", "Value=admin", ENDITEM,
"Name=LoginForm[password]", "Value=123456", ENDITEM,
"Name=LoginForm[language]", "Value=zh_cn", ENDITEM,
"Name=LoginForm[rememberMe]", "Value=0", ENDITEM,
LAST);

  运行脚本:

Action.c(): Registered web_reg_find successful for "Text=302" (count=)      [MsgId: MMSG-]
Action.c(): web_submit_data("login") was successful, body bytes, header bytes, chunking overhead bytes [MsgId: MMSG-]

  回到脚本中,修改密码为“1234567”,运行脚本进行反向验证:

Action.c(): Error -: "Text=302" not found for web_reg_find      [MsgId: MERR-]
Action.c(): web_submit_data("login") highest severity level was "ERROR", body bytes, header bytes [MsgId: MMSG-]

  至此,检查点设置成功。检查点特殊文本内容的确定需要一点点自己的分析。

3.3 关联设置

  一、为什么要设置关联,常见场景有以下两个:

  1、登录请求中,含有formhash、sessionid等特殊参数,这些参数的值每次请求将发生更新,而脚本中如果将其固定,下次请求仍然提交上次使用的参数值,请求将会失败。

  2、创建缺陷生成Bug ID,解决缺陷请求依赖该Bug ID,请求参数中Bug ID的值需要随着创建缺陷生成的Bug ID同步更新。

  下面以Bugfree解决缺陷为例,讲述如何设置关联:

  首先,在【创建缺陷】请求的响应中查找“57730”,该ID是我新创建的。

  

  截取其中一段包含“57730”的字段:

location='/bugfree/index.php/bug/57730';</

  执行Insert--new step--web_reg_save_param,其中BugID是参数名,具备一定意义即可,后续请求需要引用该参数名。

  

  生成脚本如下:

web_reg_save_param("BugID",
"LB=location='/bugfree/index.php/bug/",
"RB=';</",
"Search=All",
LAST);

  为了查看关联参数捕捉情况,开启扩展日志:  

  

  运行脚本,观察Replay Log,关联参数捕捉成功:

Action.c(): Registering web_reg_save_param was successful      [MsgId: MMSG-]
Action.c(): Notify: Saving Parameter "BugID = 57732".

  关联参数捕捉结束,接下来很简单,传递捕获的参数到后续请求中,将具体值替换成引用值即可:

  

  再次运行脚本:

Action.c(): Registering web_reg_save_param was successful      [MsgId: MMSG-]
Action.c(): Notify: Saving Parameter "BugID = 57734".
Action.c(): web_submit_data("创建缺陷") was successful, body bytes, header bytes, chunking overhead bytes [MsgId: MMSG-]
Action.c(): Notify: Parameter Substitution: parameter "BugID" = ""
Action.c(): web_submit_data("解决缺陷") was successful, body bytes, header bytes, chunking overhead bytes [MsgId: MMSG-]

  关联基本应用到此为止,后续补充复杂的关联应用,例如关联数组。

3.4 脚本调试

  脚本调试应遵循分步调试原则,可以采用【断点设置】和【单步跟踪】。更简便的方法就是利用注释,比如,先将【创建缺陷】、【解决缺陷】注释,单独放开【登录】,对其进行调试,由上至下依次进行。

  通过View--Test result可查看Html格式视图,便于排查脚本中的错误。例如下图,表明UTF-8未设置,导致中文参数值不被识别:

  

Loadrunner手动编写包含事务、检查点、关联等元素的脚本实例的更多相关文章

  1. LoadRunner系列之—-02 基于webservice协议的接口测试(脚本实例)

    Loadrunner 基于webservice协议的接口压力测试(脚本实例) 接口功能如下:请求接口,报文只有一个参数为证件号码:返回报文中,有证件号码是否能查到对应数据,查到几条数据. 思路:请求w ...

  2. 手动编写一个简单的loadrunner脚本

    loadrunner除了自动录制脚本外,还可以手动编写脚本,通过右键+inset step添加步骤,还可以手动添加事务,集合点等 下面是一个简单的Action脚本,服务是运行在本机的flask服务: ...

  3. LoadRunner ---手动关联与预关联

    手动关联                                       如果脚本很长,那么我们想找到一个脚本中哪些地方是需要关联的并不是一件容易的事情.这时,我们可以通过脚本对比的方法找 ...

  4. 【Loadrunner】Loadrunner 手动关联技术

    Loadrunner 手动关联技术 录制成功,回放失败,怀疑和动态数据有关: 1 重新录制一份脚本,两次录制的脚本进行比对,确定动态数据,复制动态数据: 2  找到第一次产生该动态数据的响应对应的相应 ...

  5. Loadrunner手动关联详解

    Loadrunner手动关联详解 一.关联的含义: 关联(correlation):在脚本回放过程中,客户端发出请求,通过关联函数所定义的左右边界值(也就是关联规则),在服务器所响应的内容中查找,得到 ...

  6. LoadRunner关联函数的脚本实例--如何操作关联参数

    LoadRunner关联函数的脚本实例--如何操作关联参数 这几天一直在学习LoadRunner的VuGen编程,今天想对关联函数web_reg_save_param做详细的试验和研究: ~f6p q ...

  7. 性能测试基础---事务&检查点&思考时间&集合点

    性能测试脚本的增强:·参数化·关联·事务·检查点·思考时间·集合点 ·事务:事务的引入是为了度量相关的业务请求的响应时间和吞吐量指标.在LR中,事务是通过两个事务函数来实现的. lr_start_tr ...

  8. 软件测试之loadrunner学习笔记-01事务

    loadrunner学习笔记-01事务<转载至网络> 事务又称为Transaction,事务是一个点为了衡量某个action的性能,需要在开始和结束位置插入一个范围,定义这样一个事务. 作 ...

  9. 性能测试总结工作总结-基于WebService协议脚本 内置函数手动编写

    LoadRunner基于WebService协议脚本 WebService协议脚本有三种生成方式,一种是直接通过LoadRunner导入URL自动解析生成:一种是使用LoadRunner内置函数手动编 ...

随机推荐

  1. Java基础-运算符(03)

    概念: 运算符:就是对于常量和变量进行操作的符号. 表达式:用运算符连接起来的符合java语法的式子,不同的运算符连接的表达式是不同类型的表达式. 运算符分类: 算数运算符(+  -  *  /  % ...

  2. C# 8.0的三个令人兴奋的新特性

    C# 语言是在2000发布的,至今已正式发布了7个版本,每个版本都包含了许多令人兴奋的新特性和功能更新.同时,C# 每个版本的发布都与同时期的 Visual Studio 以及 .NET 运行时版本高 ...

  3. Windows搭建golang开发平台

    Golang是谷歌开发的一款开源性语言,暂时比较方便的IDE有Inteillj Idea.LiteIDE.Eclipse(Golipse)等,使用起来比较方便的IDE:LiteIDE和Inteillj ...

  4. 走进 Visual Studio Mobile Center for Xamarin.Forms

    前几篇分别介绍了 Xamarin.Forms 的 MVVM 的 Prism,UITest,Nuint Test,那这样算下来,代码部分基本结构都有了(逻辑就先忽略吧) 那接下来就应该是自动 Build ...

  5. Codeforces Round #383 (Div. 2) B. Arpa’s obvious problem and Mehrdad’s terrible solution

    B. Arpa’s obvious problem and Mehrdad’s terrible solution time limit per test 1 second memory limit ...

  6. Just a Hook(区间set)

    Just a Hook Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total ...

  7. Hive中常用的查询命令

    日志数据的统计处理在这里反倒没有什么特别之处,就是一些 SQL 语句而已,也没有什么高深的技巧,不过还是列举一些语句示例,以示 hive 处理数据的方便之处,并展示 hive 的一些用法. a)    ...

  8. SVG绘制loading效果

    <div class="loading"> <svg width='40px' height='40px' xmlns="http://www.w3.o ...

  9. 整数中1出现的次数(从1到n的整数中1出现的次数)

    题目 求出1~13的整数中1出现的次数,并算出100~1300的整数中1出现的次数?为此他特别数了一下1~13中包含1的数字有1.10.11.12.13因此共出现6次,但是对于后面问题他就没辙了.AC ...

  10. 配置好postfix邮件服务器之后就可以使用它来发送邮件了

    下面是一段摘自W3school关于php mail函数的栗子,经过测试发现两个问题. <?php $to = "somebody@example.com, somebodyelse@e ...