一、前言:

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

二、准备:

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. Redis基本认识和基础学习-基本命令

    Redis 基本介绍 REmote DIctionary Server(Redis) 是一个由Salvatore Sanfilippo写的key-value存储系统. Redis是一个开源的使用ANS ...

  2. 异常详细信息: Abp.AbpException: No language defined!

    程序运行后,出现错误:No language defined! 解决方法: 1.检查是否已创建数据库,若未创建则在程序包管理控制台执行命令:Update-Database 2.检查表AbpLangua ...

  3. hihocoder 1015题

    代码 #include <iostream> #include <string> #include <typeinfo> #include <vector&g ...

  4. THE MATRIX PROBLEM

    THE MATRIX PROBLEM Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) ...

  5. Can you solve this equation?

    Can you solve this equation? Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Jav ...

  6. NumPy基础练习(练一遍搞定NumPy)

    import numpy as np import pandas as pd from numpy import random from numpy.random import randn ##### ...

  7. Nginx安装、平滑升级与虚拟机配置

    Nginx 高性能HTTP反向代理服务器,也是 LAMP/POP3/SMTP代理服务器 由内核和模块组成,内核通过找配置文件讲客户端请求映射到一个location(location是Nginx配置中的 ...

  8. 入门到熟练-Eclipse开发工具

    1. 概述 本文用于Eclipse说明开发功能的各种配置.希望可以帮助到对于Eclipse工具设置不同熟练的朋友,快速上手Eclipse开发工具. 2. Eclipse的配置 2.1. 设置Eclip ...

  9. C# 判断文件是否文本文件

    在网上查了好多资料,大部分都是通过将文件读成二进制流,取前两个字节判断,比如.jpg的是255216.代码如下: ); i++; }return isTextFile; }catch (Excepti ...

  10. Unit Of Work之我见

    本人以前写程序都是瞎写,根本没有啥模式也没有啥方法. 近一年来学习了传智的一些课程,感觉马伦老师很有才,很强大,所以学来了一个模式(应当叫模式吧,该我也不知道叫啥哈). 就是在DAL层封装一个DbSe ...