LoadRunner用户行为模拟器 《第三篇》

发表于:2017-8-17 14:56

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:逆心    来源:51Testing软件测试网采编

  用户行为模拟器简称VU,VU通过运行VU脚本模拟了用户对软件的操作行为。VU是基于网络协议的。很明显,被测服务器是通过各种各样的网络协议与客户端打交道的。VU要“骗过”被测服务器,当然就要遵守这些协议,按规矩、按步骤来执行动作,否则就会吃“闭门羹”。
  基于网络协议的脚本的一个好处是,我们可以使用相对少的硬件资源,来生成大量的虚拟用户负载。相比之下,WinRunner和QTP脚本时基于界面事件的,它在一台主机上同时只能运行一个虚拟用户的脚本,因为一个虚拟用户会占用整个主机的资源。
  所以可以有如下结论:
  1.VU不关心用户在界面发生的事情(如用户鼠标移动、填写WebForm数据)等。
  2.VU中的操作关联与界面上的操作关联是不一致的。如正常用户的操作是,打开列表页,点击一行进入详细页面。而LoadRunner记录一个请求,以及这个请求的参数直接进入,对它来说根本没有打开列表页的步骤。
  一、录制脚本
  VU通过录制用户在客户端软件的操作来直接生成脚本,用户的每个协议级的操作以LoadRunner的API函数方式记录在脚本里。回放脚本的时候,通过执行API函数来模拟最初用户的操作动作。
  1、选择协议
  协议有好多种,是用哪种协议当时你开发的时候你自然会知道。目前我一般用的都是Web(HTTP/HTML)协议。
  当我们试图创建一个新的VUser的时候,就会弹出协议选择对话框。
  有两种协议选择方式:单协议模式和多协议模式。
  (1)、单协议模式:当用户以单协议录制时,VU只录制在既定协议上的用户操作,在VU中我们可以使用单协议模式选择任何一种协议。
  (2)、多协议模式:当用户以多协议录制时,VU录制几个协议上的操作。并不是任意的协议都可以组合成多协议模式。
  2、规划脚本结构
  在录制时,用户可以选择哪些操作生成脚本在vuser_init、Action和vuser_end中,同时,也可以在录制时随时加入transaction的定义、注释和同步点。VU录制工具条如下所示:
  3、HTTP Vuser中的URL mode和HTML mode
  在录制之前,我们需要设置录制选项:

  在默认情况下,选择“HTML-based script”,说明脚本中采用HTML页面的形式来表示,这种方式的Script脚本容易维护,容易理解,推荐以这种方式录制。
  “URL-based script”说明脚本中的表示采用基于URL的方式,所有的HTTP的请求都会被录制下来,单独生成函数,所以URL模式生成的脚本显得有些杂乱。
  Action()
  {
      web_url("Login", 
          "URL=http://127.0.0.1:9090/Account/Login", 
          "Resource=0", 
          "RecContentType=text/html", 
          "Referer=", 
          "Snapshot=t1.inf", 
          "Mode=HTML", 
          LAST);
  }
  而以HTML模式录制,则生成如下脚本:
  Action()
  {
      web_url("Login", 
          "URL=http://127.0.0.1:9090/Account/Login", 
          "Resource=0", 
          "RecContentType=text/html", 
          "Referer=", 
          "Snapshot=t1.inf", 
          "Mode=HTTP", 
          LAST);
      web_url("Default.css", 
          "URL=http://127.0.0.1:9090/Resources/CSS/Default.css", 
          "Resource=1", 
          "RecContentType=text/css", 
          "Referer=http://127.0.0.1:9090/Account/Login", 
          "Snapshot=t4.inf", 
          LAST);
      web_url("gwu1.jpg", 
          "URL=http://127.0.0.1:9090/Resources/Images/login/gwu1.jpg", 
          "Resource=1", 
          "RecContentType=image/jpeg", 
          "Referer=http://127.0.0.1:9090/Account/Login", 
          "Snapshot=t5.inf", 
          LAST);
    ... 省略N个
  }
  是选择HTML还是URL录制,有以下参考原则:
  1.基于浏览器的应用程序推荐使用HTML-based script。
  2.不是基于浏览器的应用程序推荐使用URL-based script。
  3.如果基于浏览器的应用程序中包含了JavaScript并且该脚本向服务器产生了请求,比如DataGrid分页按钮等,也要使用URL-based script方式录制。
  4.基于浏览器的应用程序中使用了HTTPS安全协议,使用URL-based script方式录制。
  4、查看日志
  在录制和回放的时候,VU会分别把发生的事件记录成日志文件,这些日志有利于我们跟踪VU和服务器的交互过程。我们可以通过VU输出窗口观察日志,也可以到脚本目录中直接查看文件。
  1、执行日志(Execution Log,新版本是Replay Log)
  脚本运行时的输出都记在这个Log里。
  “执行日志”中使用了不同颜色的文本。
  1.黑色:标准输出信息。
  2.红色:标准错误信息。
  3.绿色:用引号括起来的文字字符串(例如URL)。
  4.蓝色:事务信息(开头、结束、状态和持续时间)。
  2、录制脚本(Recording Log)
  当录制脚本时,Vugen会拦截Client端(浏览器)与Server端(服务器)之间的对话,并且通通记录下来,产生脚本。在Vugen的Recording Log中,我们可以找到浏览器与服务器之间所有的对话,包含通信内容、日期、事件、浏览器的请求、服务器的响应内容等。脚本和Recording Log最大的差别在于,脚本只记录了Client端要对Server端的请求内容,而Recording Log则是完整记录二者的对话。所以,通过录制日志,我们能够更加清楚地看到客户端与服务器的交互。
  3、产生日志(Generation Log)
  产生日志记录了脚本录制的设置、网络事件到脚本函数的转化过程。
  提示:脚本能正常运行后应禁用日志。因为产生及写入日志需占用一定资源。
  二、回放脚本
  单击run按钮,或按快捷键“F5”就可以运行脚本。VU脚本运行工具条如下:
  录制完成之后,最好先运行一次脚本,因为在跑测试之前必须先确保脚本没有错误。
  三、关联
  关联的作用是客户端每次的访问,服务器都会有动态的内容产生,如果这个动态内容跟不上,则服务器就报错的情况。如SessionId,假如每次访问,服务器都为其分配一个session号(随机的)导致报错时,此时就要对seesion做关联。
  这个看起来好像很难的样子,先跳过, 用到再学。
  四、脚本视图和树视图
  VU提供两种视图来查看脚本的内容,一个是脚本视图,另一个是基于图标的树视图。
  所有类型的Vuser都有文本脚本视图,但是只有特定的Vuser才会有树视图。
  1、树视图(Tree View)
  Tree View也叫做基于icon的View,也就是说,脚本的每个函数在Tree View中都以一个带有icon的节点来代替。可以点击工具栏=>"Tree"按钮或者在“View”=>“Tree View”,显示VU树视图。
  Tree View的好处是使用户更方便地修改脚本,Tree View支持拖拽,用户可以把任意一个节点拖拽到他想要的地方,从而达到修改脚本的目的。用户可以右键单击节点,进行修改/删除当前函数参数属性,增加函数等操作,通过Tree View能够增加LoadRunner提供的部分常用通用函数和协议相关函数。比如Web Service Vuser就不能通过Tree View参数化一些复杂的数据类型,在这种情况下,就需要Script View了。
  2、脚本视图(Script View)
  在Script View中能够看到一行行的API函数,Script View适合一些高级用户,通过Script View向脚本中增加一些其他的API函数。可以单击工具栏上的"Script"按钮或者在"View"菜单下选择"Script View",显示VU脚本视图。
  当用户在Script View中对脚本做了修改之后,Tree View也会做相应的变化。如果脚本有语法错误,Script View将不能转化为Tree View或缩略图。
  3、理解Snapshot
  napshot,顾名思义,就是快照,代表当前的step,Snapshot显示了客户端执行完当前step后的样子,在Tree View右侧的frame中可以查看Snapshot,在LoadRunner 8.0中,Snapshot包含Page View、Client Request和Server Response。
  Snapshot有两种生成方式,一种是在record的时候生成,另一种是在replay的时候生成。可以对比两种方式生成的Snapshot,以发现哪些是动态值,需要参数化。
  五、事务、同步点和思考时间
  1、Transaction(事务)
  在LoadRunner里,我们定义事务主要是为了度量服务器的性能。每个事务度量服务器响应指定的Vuser请求所有的时间,这些请求可以是简单任务,也可以是复杂任务。
  要度量事务,需要插入Vuser函数以标记任务的开始和结束。在脚本内,可以标识的事务不受数量限制,每个事务的名称都不同。
  在场景执行期间,Controller将度量执行每个事务所用的时间。场景运行后,可使用LoadRunner的图和报告来分析各个事务的服务器性能。
  设置Transaction的方法如下:
  1.选择新Transaction开始点,在被度量脚本段之前插入lr_start_transaction。
  2.选择新Transaction结束点,在被度量脚本段之后插入lr_end_transaction。
  下面的脚本例子中将登陆操作设为一个名为"login"的事务:
  lr_start_transaction("login_start");
  web_submit_data("login", 
  "Action=http://127.0.0.1:9090/account/login", 
  "Method=POST", 
  "RecContentType=text/html", 
  "Referer=http://127.0.0.1:9090/Account/Login", 
  "Snapshot=t19.inf", 
  "Mode=HTTP", 
  ITEMDATA, 
  "Name=userName", "Value=xpj", ENDITEM, 
  "Name=submitBtn", "Value= ", ENDITEM, 
  "Name=password", "Value=123", ENDITEM, 
  LAST);
  lr_end_transaction("login_end",LR_AUTO);
  如果手工插入的Transaction如果称为“显式事务”的话,那么LoadRunner还提供了一种“隐式事务”的机制,在VU的Run-time Settings中又称为“自动事务”。
  在Run-time Settings中,在Miscellaneous选项卡的Automatic Transactions中定义自动事务。
  Vuser => Run-time Setting => Miscellaneous
  可以设置LoadRunner直接按事务处理Vuser中的每个Action或step。这里,Action指的是vuser_init、Action和vuser_end三大函数,而step指的是LoadRunner执行的每个函数。LoadRunner将Action名或step指定为事务名。默认情况下,将启用按Action使用自动事务的功能。
  1.要禁用按操作使用自动事务的功能,清除"Define each action as a transaction"复选框(默认情况下启用)。
  2.要启用按步骤使用自动事务的功能,选中"Define each step as a transaction"复选框。
  Transaction的开始点和结束点必须在一个Action中,跨越多个Action是不允许的。Transaction的名字在脚本中必须是唯一的,当然也包括在多个Action的脚本中唯一。你也可以在一个Transaction中创建另外一个Transaction,叫做Nested Transaction。
  2、Rendezvous Point同步点
  在系统上模拟较重的用户负载,需要同步各个Vuser以便在同一时刻执行任务。通过创建集合点,可以确保多个Vuser同时执行操作。当某个Vuser到达该集合点时,Controller会将其保留,直到参与该集合的全部Vuser到达。Controller才允许Vuser执行。
  可通过将集合点插入到Vuser脚本中来指定回合位置。在Vuser执行脚本并遇到集合点时,脚本将暂停执行,Vuser将等待Controller的允许才继续执行。Vuser被从集合释放后,将执行脚本中的下一个任务。
  lr_rendezvous("the begin port");  //集合点
      web_submit_data("login", 
          "Action=http://127.0.0.1:9090/account/login", 
          "Method=POST", 
          "RecContentType=text/html", 
          "Referer=http://127.0.0.1:9090/Account/Login", 
          "Snapshot=t19.inf", 
          "Mode=HTTP", 
          ITEMDATA, 
          "Name=userName", "Value=xpj", ENDITEM, 
          "Name=submitBtn", "Value= ", ENDITEM, 
          "Name=password", "Value=4297F44B13955235245B2497399D7A93", ENDITEM, 
          LAST);
  注意:
  1.只能在Action中添加集合点(不能在vuser_init或vuser_end中添加)。
  2.同步点只有多用户并发的场景,同步点的意义才表现出来。
  3、注释
  LoadRunner支持C语言的注释方法:
  多行注释:
  /*
      这是多行注释
  */
  单行注释:
  //这是单行注释
  4、Think Time(思考时间)
  用户在执行两个连续操作期间等待的时间成为“思考时间”。Vuser使用lr_think_time函数模拟用户思考时间。录制Vuser脚本时,Vugen将录制实际的思考时间并将相应的lr_think_time脚本插入到Vuser脚本。此功能通过lr_think_time实现。
  lr_think_time参数的单位是秒,比如lr_think_time(5)意味着LoadRunner执行到此条语句时,停留5秒,然后再继续执行后面的语句。
  如果不想在脚本中执行Think Time语句,需要逐条语句删除,这是非常麻烦,LoadRunner提供了再Run-time Settings中可以设置直接忽略Think Time,而不用修改脚本。
  有Think Time比没有Think Time的脚本对服务器造成的压力更小,但是有Think Time才是更符合用户的实际工作场景的。
  Vuser => Run-time Settings => General => Think Time
  六、数据驱动-参数化(Parameters)
  数据驱动就是把测试脚本和测试数据分离开来的一种思想,脚本体现测试流程,数据体现测试案例。数据不写死在脚本里面,这样大大提高了脚本的可复用性。
  1、为什么需要参数化
  在录制程序运行的过程中,Vugen(脚本生成器)自动生成了脚本以及录制过程中实际用到的数据。在这个时候,脚本和数据是混在一起的。
  如登录操作:
  web_submit_data("login", 
          "Action=http://127.0.0.1:9090/account/login", 
          "Method=POST", 
          "RecContentType=text/html", 
          "Referer=http://127.0.0.1:9090/Account/Login", 
          "Snapshot=t19.inf", 
          "Mode=HTTP", 
          ITEMDATA, 
          "Name=userName", "Value=xpj", ENDITEM, 
          "Name=password", "Value=123123", ENDITEM, 
          LAST);
  在登录操作中,很明显xpj与123123是填入的数据,如果Controller里以多用户方式运行这个脚本的时候,每个虚拟用户都会以同样的用户名"robin"、密码"123123"去登录系统。这样做性能测试,不太眼睛,服务器大多会采用缓存功能提高系统性能,以同样的用户名/密码登录系统的缓存命中率会很高,也要快得多。
  因此,LoadRunner支持参数变量。
      web_submit_data("login", 
          "Action=http://127.0.0.1:9090/account/login", 
          "Method=POST", 
          "RecContentType=text/html", 
          "Referer=http://127.0.0.1:9090/Account/Login", 
          "Snapshot=t19.inf", 
          "Mode=HTTP", 
          ITEMDATA, 
          "Name=userName", "Value={username}", ENDITEM, 
          "Name=password", "Value={password}", ENDITEM, 
          LAST);
  参数化后,用户名xpj被一个参数{username}替换,密码被另外一个参数{password}替换。其中{username}和{password}分别和参数文件关联,在脚本运行时,用户名和密码的值从参数{username}和{password}中获得。而我们会在后面介绍LoadRunner有一套机制来保证参数的使用和变化,这样就实现了脚本与数据的分离。
  参数化是我们学习LoadRunner中经常用到的功能。除了实现数据驱动之外,参数化脚本还有以下两个优点:
  1.可以使脚本的长度变短;
  2.可以增强脚本的可读性和可维护性;
  实际上,参数化的过程如下:
  1.在脚本中用参数取代常量值;
  2.设置参数的属性以及数据源;
  2、参数的创建
  LoadRunner对脚本中参数个数没有限制,我们可以在一个脚本中创建任意多个参数。
  选择参数类型:
  Parameter name:输入参数名称;
  Parameter type:选择参数类型;
  参数类型说明
  1.Data Files:这是我们最长使用的一种参数类型,它的数据存在于文件中。该文件的内容可以手工添加,也可以利用LoadRunner的Data Wizard从数据库中导出。
  2.User-Defined Functions:调用外部DLL函数生成的数据
  3.Internal Data:虚拟用户内部产生的数据。Internal Data包括以下几种类型:
  Date/Time:用当前的日期/事件替换参数。要指定一个Date/Time的格式,菜单中可以选择格式。格式要与脚本中录制的格式保持一致。
  Group Name:用虚拟用户组名称替换参数。在创建scenario的时候,你可以指定虚拟用户组的名称。
  Load Generator Name:用脚本负载生成器的名称替换参数。负载生成器是虚拟用户在运行的计算机。
  Iteration Number:用当前的迭代数目替换参数。
  Random Number:用一个随机数替换参数。通过指定最大值和最小值来设置随机数的范围。
  Unique Number:用一个唯一的数字来替换参数。你可以指定一个起始数字和一个块的大小。
  VuserID:用分配给虚拟用户的ID替换参数,ID是由LoadRunner的控制器在scenario运行时生成的。如果从脚本生成器运行脚本的话,虚拟用户的ID总是-1.
  然后为该参数设置不同的值。

  如果想用以前定义过的参数来代替常量字符串的话,选中该字符串,单击右键,然后选择“Use existing parameters”,从弹出的子菜单中选择参数,或者用"Select from Parameter List"来打开参数列表对话框。
  对于已经用参数替换过的地方,如果想取回原来的值,那么就在参数上单击右键,然后选择"Restore Original value"。
  不是所有的数据都可以参数化
  在LoadRunner中,只有函数的参数才能参数化,不能参数化非函数参数的数据。
  如lr_eval_string,我们可以在Vuser脚本中的任何地方使用它来参数化数据,lr_eval_string用来得到一个参数的值,而参数可以预先在LoadRunner的Parameter List里定义好,也可以是之前通过其他函数创建的。
  //通过lr_save_datetime把七天后的时间保存在date参数中
  lr_save_datetime("%d %m %y", DATE_NOW + (ONE_DAY * 7),"date");
  //通过lr_eval_string把date参数中的值取出来,lr_output_message的输出值为七天后的时间
  lr_output_message("Date is s%",lr_eval_string("{date}"));
  更多的函数可以翻查LoadRunner函数手册。lr_eval_string函数的返回值是一个指向参数值的指针,如果这个指针向的内存是LoadRunner内部分配的,每次Iteration后自动释放。如果在Iteration中还有多层循环进行参数化,那么最好不要使用lr_eval_string了,这会导致内存迟迟不能释放。在这种情况下,应该使用lr_eval_string_ext,同时配对使用lr_eval_string_ext_free来及时释放内存。

21/212>
《2023软件测试行业现状调查报告》独家发布~

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号