发布新日志

  • 录制脚本中碰到两个问题

    2009-06-15 18:17:34

    1. web_url("indexAction.do") highest severity level was "ERROR", 834156 body bytes, 3480 header bytes, 288 chunking overhead bytes

    经过查找后,网上资料是

    方法一:
    1, 打开recording options,在internet protocol下的recording中选择recording levelHTML-based script,点击HTML Advanced,选择script. typeA script. containing explicit.即可。
    2, 选择使用URL_based script录制。

    方法二:
    取消选中run time settings-browser emulation-download non-html resources.解决 

    2.Error -27727: Step download timeout (240 seconds) has expired when downloading resource(s)

    •A、应用服务参数设置太大导致服务器的瓶颈
    •B、页面中图片太多
    •C、在程序处理表的时候检查字段太大多
  • LoadRunner的脚本回放问题解决(转)

    2009-06-12 19:29:40

    在运行脚本回放过程中,有时会出现错误,这在实际测试中是不可避免的,毕竟自动录制生成的脚本难免会有问题,需要运行脚本进行验证,把问题都解决后才加入到场景中进行负载测试。下面结合常用的协议(如Web、Web Services协议)录制的脚本进行回放时出现的问题介绍一下解决的方法。

      需要注意的是,回放脚本时出现的错误有时是程序自身的原因导致的,因此在解决脚本回放问题前必须保证程序录制出的脚本是正确的。

      1.LoadRunner超时错误:在录制Web协议脚本回放时超时情况经常出现,产生错误的原因也有很多,解决的方法也不同。

      错误现象1:Action.c(16): Error -27728: Step download timeout (120 seconds) has expired when downloading non-resource(s)。

      错误分析:对于HTTP协议,默认的超时时间是120秒(可以在LoadRunner中修改),客户端发送一个请求到服务器端,如果超过120秒服务器端还没有返回结果,则出现超时错误。

      解决办法:首先在运行环境中对超时进行设置,默认的超时时间可以设置长一些,再设置多次迭代运行,如果还有超时现象,需要在“Runtime Setting”>“Internet Protocol:Preferences”>“Advanced”区域中设置一个“winlnet replay instead of sockets”选项,再回放是否成功。

      错误现象2:Action.c(81):Continuing after Error -27498: Timed out while processing URL=http://172.18.20.70:7001/workflow/bjtel/leasedline/ querystat/ subOrderQuery.do

      错误分析:这种错误常常是因为并发压力过大,服务器端太繁忙,无法及时响应客户端的请求而造成的,所以这个错误是正常现象,是压力过大造成的。

      如果压力很小就出现这个问题,可能是脚本某个地方有错误,要仔细查看脚本,提示的错误信息会定位某个具体问题发生的位置。

      解决办法:例如上面的错误现象问题定位在某个URL上,需要再次运行一下场景,同时在其他机器上访问此URL。如果不能访问或时间过长,可能是服务器或者此应用不能支撑如此之大的负载。分析一下服务器,最好对其性能进行优化。

      如果再次运行场景后还有超时现象,就要在各种图形中分析一下原因,例如可以查看是否服务器、DNS、网络等方面存在问题。

      最后,增加一下运行时的超时设置,在“Run-Time Settings”>“Internet Protocol:Preferences”中,单击“options”,增加“HTTP-request connect timeout” 或者“HTTP-request receive”的值。

      2.LoadRunner脚本中出现乱码:在录制Web协议脚本时出现中文乱码,在回放脚本时会使回放停止在乱码位置,脚本无法运行。

      错误现象:某个链接或者图片名称为中文乱码,脚本运行无法通过。

      错误分析:脚本录制可能采用的是URL-based scrīpt方式,如果程序定义的字符集合采用的是国际标准,脚本就会出现乱码现象。

      解决办法:重新录制脚本,在录制脚本前,打开录制选项配置对话框进行设置,在“Recording Options”的“Advanced”选项里先将“Surport Charset”选中,然后选中支持“UTF-8”的选项。

      3.LoadRunner HTTP服务器状态代码:在录制Web协议脚本回放脚本的过程中,会出现HTTP服务器状态代码,例如常见的页面-404错误提示、-500错误提示。

      错误现象1:-404 Not Found服务器没有找到与请求URI相符的资源,但还可以继续运行直到结束。

      错误分析:此处与请求URI相符的资源在录制脚本时已经被提交过一次,回放时不可再重复提交同样的资源,而需要更改提交资源的内容,每次回放一次脚本都要改变提交的数据,保证模拟实际环境,造成一定的负载压力。

      解决办法:在出现错误的位置进行脚本关联,在必要时插入相应的函数。

      错误现象2:-500 Internal Server Error服务器内部错误,脚本运行停止。

      错误分析:服务器碰到了意外情况,使其无法继续回应请求。

      解决办法:出现此错误是致命的,说明问题很严重,需要从问题的出现位置进行检查,此时需要此程序的开发人员配合来解决,而且产生的原因根据实际情况来定,测试人员无法单独解决问题,而且应该尽快解决,以便于后面的测试。

      4.LoadRunner请求无法找到:在录制Web协议脚本回放脚本的过程中,会出现请求无法找到的现象,而导致脚本运行停止。

      错误现象:Action.c(41): Error -27979: Requested form. not found [MsgId: MERR-27979]

      Action.c(41): web_submit_form. highest severity level was "ERROR",0 body bytes, 0 header bytes [MsgId: MMSG-27178]"

      这时在tree view中看不到此组件的相关URL。

      错误分析:所选择的录制脚本模式不正确,通常情况下,基于浏览器的Web应用会使用“HTML-based scrīpt”模式来录制脚本;而没有基于浏览器的Web应用、Web应用中包含了与服务器进行交互的Java Applet、基于浏览器的应用中包含了向服务器进行通信的Javascrīpt/VBscrīpt代码、基于浏览器的应用中使用HTTPS安全协议,这时则使用“URL-based scrīpt”模式进行录制。

      解决办法:打开录制选项配置对话框进行设置,在“Recording Options”的“Internet Protocol”选项里的“Recording”中选择“Recording Level”为“HTML-based scrīpt”,单击“HTML Advanced”,选择“scrīpt Type”为“A scrīpt containing explicit”。然后再选择使用“URL-based scrīpt”模式来录制脚本。

      5.LoadRunner不执行检查方法:在录制Web协议脚本中添加了检查方法Web_find,但是在脚本回放的过程中并没有执行。

      错误现象:在脚本中插入函数Web_find,在脚本中设置文本以及图像的检查点,但是在回放过程中并没有对设置的检查点进行检查,即Web_find失效。

      错误分析:由于检查功能会消耗一定的资源,因此LoadRunner默认关闭了对文本以及图像的检查,所以在设置检查点后,需要开启检查功能。

      解决办法:打开运行环境设置对话框进行设置,在“Run-time Settings”的“Internet Protocol”选项里的“Perference”中勾选“Check”下的“Enable Image and text check”选项。

      6.LoadRunner回放Web Services协议脚本错误:LoadRunner 8.0版本在录制Web Services协议的脚本时正常,但在回放时会出现错误,提示停止脚本运行。

      错误现象:利用LoadRunner 8.0版本来录制Web Services协议的脚本没有任何错误提示,回放脚本时会出现如下错误提示“Error:server returned an incorrectly formatted SOAP response”。

      错误分析:出现此错误的原因是LoadRunner8.0在录制Web Services协议的脚本时存在一个缺陷:如果服务器的操作系统是中文的,VuGen会自动将WSDL文件的头改为<?xml version="1.0"encoding="zh_cn" ?>,所以才会有此错误提示。

      解决办法:下载两个补丁,分别为“LR80WebServicesFPI_setup.exe”和“lrunner_web_ services_patch_1.exe”安装上即可。


  • 完善增强脚本

    2009-05-25 13:40:28

        首先,为了衡量服务器的性能,需要定义事务(Transaction)。例如在脚本中有一个数据查询操作,为了衡量服务器执行查询操作的性能,可以把这个操作定义为一个事务。这样在运行测试脚本时,LoadRunner运行到该事务的开始点时,就会开始计时,直到运行到该事务的结束点,计时结束。这个事务的运行时间在测试结果中会有反映。 LoadRunner允许在脚本中插入不限数量的事务。

      在方案执行期间,控制台将测量执行每个事务所用的时间。方案运行后,可使用LoadRunner的图和报告来分析各个事务的服务器性能。

      其次,使用集合点是为了衡量在加重负载的情况下服务器的性能情况。在测试计划中,可能会要求系统能够承受多人同时提交数据,LoadRunner通过在提交数据操作前面加入集合点的方法,检查同时有多少用户运行到集合点,人数不足时,LoadRunner会命令已经到集合点的用户等待,当在集合点等待的用户达到要求容纳的人数(如1000人)时,LoadRunner向系统提交数据。

      在脚本中加入集合点后,控制台运行脚本时,可以对集合点进行策略设置,这样就可以根据实际情况在系统上模拟用户负载了。

      再次,在录制过程中最好加入注释,因为在录制完脚本后看到的都是脚本代码,操作复杂的业务无法找到相应的位置进行关联或者参数化的动作,这时,注释就显得尤为重要。

      最后,LoadRunner提供了很多函数,有些函数是在录制时根据不同的协议自带的函数。其中有些函数是供手工添加的,这就要根据实际情况进行添加了。例如脚本关联,有些变量无法实现系统自动关联,只能添加函数进行手动关联。

      在录制完成的脚本中,还可以根据实际情况,添加事务、集合点、注释、函数等内容来增强脚本,进一步完善。下面逐一进行介绍。

      1.插入事务

      脚本中插入事务既可以在录制过程中直接插入,也可以在脚本录制结束后经编辑插入。建议采用在脚本的录制过程中插入事务的方法,这样不至于遗漏程序中应插入事务的操作。

      在需要插入事务的操作前,通过工具栏上的“Start Transaction”(开始事务)按钮插入事务,事务的名称最好有意义,这样在最后分析系统时,有助于发现系统的瓶颈点是否在具体的事务中。

      具体的操作方法如下:在录制Vuser脚本时,在需要定义事务的操作前面,单击“录制”工具栏上的“Start Transaction”菜单项,将打开“Start Transaction”对话框,如图2-23所示。

      接着出现如图2-24所示的对话框。

         

      图2-23  插入事务开始点                         图2-24  输入事务开始名称

      在给事务起名字时,事务名必须以字母或数字开始,可以包含字母、数字或者下列字符:!、$、%、&、'、-、[、^、_、`、<、>、{、}、|或~。填写好事务名称后,就可以对系统进行操作,单击“OK”接受该事务名称。

      VuGen将自动在Vuser脚本中插入事务的起始标志(“lr_start_transaction”)和终点标志(“lr_end_transaction”)。起点和终点之间的内容就是录制或者编写的测试事务脚本.
    在录制脚本过程中,随时可以单击“录制”工具栏上的“End Transaction”菜单项,结束录制,如图2-25所示。

      

      图2-25  插入事务结束点

      此时会出现如图2-26所示的结束事务的对话框。

      单击“Transaction Name”下拉框的箭头获得已打开事务的列表,选择要关闭的事务。事务的状态在默认情况下是LR_AUTO。一般情况下,也不需要修改,除非在手工编写代码时,有可能需要手动设置事务的状态。单击“OK”按钮接受该事务名称。

      脚本中事务的代码如图2-27所示。

                     

      图2-26  选择要结束事务的名称                        图2-27  插入事务图例

      当结束事务时,通过工具栏上的“End Transaction”按钮,结束事务。在结束列表中会显示最近定义的事务的名称,只要选择自己新建的事务的名称即可结束该事务。

      这样就完成了事务的插入操作。

      2.插入集合点

      集合点只能在Action中插入,不能在vuser_init或vuser_end中插入。

      在需要插入集合点的操作前,通过工具栏上的集合点按钮插入集合点,并在集合点的输入框中输入集合点的名称。集合点的名称最好是有意义的名称,这样有助于在系统分析时,分析系统的瓶颈所在。

      插入集合点具体的操作方法如下:在录制Vuser脚本时,在需要插入集合点的位置,单击“录制”工具栏上的“集合点”按钮或单击“Insert”菜单下的“Rendezvous”子菜单。将打开“Rendezvous”(集合点)对话框,如图2-28所示。

      

      图2-28  插入集合点

      接着,出现如图2-29所示的对话框。输入该集合点的名称,注意,名称最好能够清楚地说明该集合点所完成的动作。脚本中集合点的代码如图2-30所示。

              

      图2-29  输入集合点名称                图2-30  插入集合点图例

  • LoadRunner函数

    2009-05-13 14:07:21

    事务函数:
    lr_end_sub_transaction 标记子事务的结束以便进行性能分析
    lr_end_transaction 标记 LoadRunner 事务的结束
    lr_end_transaction_instance 标记事务实例的结束以便进行性能分析
    lr_fail_trans_with_error 将打开事务的状态设置为 LR_FAIL 并发送错误消息
    lr_get_trans_instance_duration 获取事务实例的持续时间(由它的句柄指定)
    lr_get_trans_instance_wasted_time 获取事务实例浪费的时间(由它的句柄指定)
    lr_get_transaction_duration 获取事务的持续时间(按事务的名称)
    lr_get_transaction_think_time 获取事务的思考时间(按事务的名称)
    lr_get_transaction_wasted_time 获取事务浪费的时间(按事务的名称)
    lr_resume_transaction 继续收集事务数据以便进行性能分析
    lr_resume_transaction_instance 继续收集事务实例数据以便进行性能分析lr_set_transaction_instance_status 设置事务实例的状态
    lr_set_transaction_status 设置打开事务的状态
    lr_set_transaction_status_by_name 设置事务的状态
    lr_start_sub_transaction 标记子事务的开始
    lr_start_transaction 标记事务的开始
    lr_start_transaction_instance 启动嵌套事务(由它的父事务的句柄指定)
    lr_stop_transaction 停止事务数据的收集
    lr_stop_transaction_instance 停止事务(由它的句柄指定)数据的收集
    lr_wasted_time 消除所有打开事务浪费的时间

    命令行分析函数
    lr_get_attrib_double 检索脚本命令行中使用的 double 类型变量
    lr_get_attrib_long 检索脚本命令行中使用的 long 类型变量
    lr_get_attrib_string 检索脚本命令行中使用的字符串

    信息性函数
    lr_user_data_point 记录用户定义的数据示例
    lr_whoami 将有关 Vuser 脚本的信息返回给 Vuser 脚本
    lr_get_host_name 返回执行 Vuser 脚本的主机名
    lr_get_master_host_name 返回运行 LoadRunner Controller 的计算机名

    字符串函数
    lr_eval_string 用参数的当前值替换参数
    lr_save_string 将以 NULL 结尾的字符串保存到参数中
    lr_save_var 将变长字符串保存到参数中
    lr_save_datetime 将当前日期和时间保存到参数中
    lr _advance_param 前进到下一个可用参数
    lr _decrypt 解密已编码的字符串
    lr_eval_string_ext 检索指向包含参数数据的缓冲区的指针
    lr_eval_string_ext_free 释放由 lr_eval_string_ext 分配的指针
    lr_save_searched_string 在缓冲区中搜索字符串实例,并相对于该字符串实例,将该缓冲区的一部分保存到参数中

    消息函数
    lr_debug_message 将调试信息发送到输出窗口
    lr_error_message 将错误消息发送到输出窗口
    lr_get_debug_message 检索当前消息类
    lr_log_message 将消息发送到日志文件
    lr_output_message 将消息发送到输出窗口
    lr_set_debug_message 设置调试消息类
    lr_vuser_status_message 生成带格式的输出,并将其写到 ControllerVuser 状态区域
    lr_message 将消息发送到 Vuser 日志和输出窗口

    运行时函数
    lr_load_dll 加载外部 DLL
    lr_peek_events 指明可以暂停 Vuser 脚本执行的位置
    lr_think_time 暂停脚本的执行,以模拟思考时间(实际用户在操作之间暂停以进行思考的时间)
    lr_continue_on_error 指定处理错误的方法
    lr_rendezvous 在 Vuser 脚本中设置集合点

  • (转)web_custom_request应用示例

    2009-03-26 17:18:38

    LoadRunner提供的web_custom_request函数可以用于实现参数的动态生成。在LoadRunner中,web_reg_save_param和custom_request都常于处理参数的动态生成。

    web_reg_save_param函数是大家都已经熟悉的了,它的主要作用是从一个response中获得后续的request需要使用的数据,然后将其作为一个参数保存下来,供后续步骤使用。该方法在LoadRunner中被称为Correlation(关联)。

    而web_custom_request函数则可以用于完全自定义向服务端发送的request。

    接下来我们用一个实际的例子说明一下web_custom_request的具体应用:

    以Mercury自带的MercuryWebTours例子为例,假设我们希望在登录进入后将用户的前两条记录删除,我们来看看用web_custom_request如何实现这个目标。

    首先,我们尝试用HTML方式对该操作进行录制。录制后的脚本中与删除相关的部分大致如下:

    web_url("welcome.pl",
        
    "URL=http://localhost/MercuryWebTours/welcome.pl?page=itinerary",
            
    "Resource=0",
            
    "RecContentType=text/html",
        
    "Referer=http://localhost/MercuryWebTours/nav.pl?page=menu&in=home",
        
    "Snapshot=t3.inf",
        
    "Mode=HTML",
        EXTRARES,
        
    "URL=images/in_itinerary.gif""Referer=http://localhost/MercuryWebTours/nav.pl?page=menu&in=itinerary", ENDITEM,
        
    "URL=images/home.gif""Referer=http://localhost/MercuryWebTours/nav.pl?page=menu&in=itinerary", ENDITEM,
            LAST);
    lr_think_time(
    2);

    web_submit_form(
    "itinerary.pl",
        
    "Snapshot=t4.inf",
        ITEMDATA,
        
    "Name=1""Value=on", ENDITEM,
        
    "Name=2""Value=on", ENDITEM,        "Name=removeFlights.x""Value=116", ENDITEM,
        
    "Name=removeFlights.y""Value=8", ENDITEM,
        LAST);

    我们通过树型模式查看一下在submit form的时候实际向服务器发出的请求的内容:

    从请求内容中可以看到,我们通过POST方法发出了请求,请求发送的目的URL是/MercuryWebTours/itinerary.pl,发送的内容是:
    "1=on&flightID=384-798-JM&2=on&flightID=3026-1592-JM&3=on&flightID=1194-2326-JM&.cgifields=1&.c"
    "gifields=2&.cgifields=3&removeFlights.x=116&removeFlights.y=8"

    从发送的内容中可以很明显的分析得出,1=on表示第一个checkbox是被选中的,flightID=384-798-JM表示的是第一条记录所对应的flightID。因此,如果我们需要自己组成这个发送的request的话,必须首先通过关联的方式获得前两条记录的flightID,然后再组成request的内容。

    web_custom_request方法的原型是:
    int web_custom_request (const char *RequestName, <List of Attributes>,[EXTRARES, <List of Resource Attributes>,] LAST );

    其中List of Attributes的主要项目是Method,URL和BODY等。对这个例子来说,我们可以很容易构造出我们需要的request的BODY内容。
    ……
     strcpy(creq, "Body=1=on&flightID=");
     strcat(creq, lr_eval_string("{fID1}"));
     strcat(creq, "&2=on&flightID=");
     strcat(creq, lr_eval_string("{fID2}"));
     strcat(creq, "&.cgifields=1&.cgifields=2");
     strcat(creq, "&removeFlights.x=116&removeFlights.y=8");
    ……

    其中{fID1}、{fID2}等都是通过关联获得的flightID的数据。

    因此,我们可以根据图中的数据编写custom_request语句:

    web_custom_request("itinerary.pl",
    "Method=POST"
        
    "URL=http://localhost/MercuryWebTours/itinerary.pl",
        
    "RecContentType=text/xml",
        creq,
        
    "Snapshot=t4.inf",
        LAST);

    较为完整的代码如下:
    Action()
    {
        
    char creq[500];

        web_reg_save_param(
    "fID1""LB=INPUT TYPE=\"hidden\" NAME=\"flightID\" VALUE=\"""RB=\"""ORD=1"
            
    "SEARCH=BODY", LAST);
        web_reg_save_param(
    "fID2""LB=INPUT TYPE=\"hidden\" NAME=\"flightID\" VALUE=\"""RB=\"""ORD=2"
            
    "SEARCH=BODY", LAST);
        web_url(
    "welcome.pl",
            
    "URL=http://localhost/MercuryWebTours/welcome.pl?page=itinerary",
            
    "Resource=0",
            
    "RecContentType=text/html",
            
    "Referer=http://localhost/MercuryWebTours/nav.pl?page=menu&in=home",
            
    "Snapshot=t3.inf",
            
    "Mode=HTML",
            EXTRARES,
            
    "URL=images/in_itinerary.gif""Referer=http://localhost/MercuryWebTours/nav.pl?page=menu&in=itinerary", ENDITEM,
            
    "URL=images/home.gif""Referer=http://localhost/MercuryWebTours/nav.pl?page=menu&in=itinerary", ENDITEM,
            LAST);
        lr_think_time(
    2);

        strcpy(creq, 
    "Body=1=on&flightID=");
        strcat(creq, lr_eval_string(
    "{fID1}"));
        strcat(creq, 
    "&2=on&flightID=");
        strcat(creq, lr_eval_string(
    "{fID2}"));
        strcat(creq, 
    "&.cgifields=1&.cgifields=2");
        strcat(creq, 
    "&removeFlights.x=116&removeFlights.y=8");

        lr_output_message(creq);

        web_custom_request(
    "itinerary.pl",
    "Method=POST"
            
    "URL=http://localhost/MercuryWebTours/itinerary.pl",
            
    "RecContentType=text/xml",
            creq,
            
    "Snapshot=t4.inf",
            LAST);

        
    return 0;
    }
  • (转)LoadRunner脚本解释分析

    2009-03-21 17:05:33

    1、获得网站首页
        web_url("www.seventest.net",
            "URL=www.seventest.net/",
            "TargetFrame=",  //
    目标窗口_BLANK:打开一个新窗口
                                              _PARENT:
    取代最后一个窗口的父窗口
                                              _SELF:
    取代最后一个窗口

                                              _TOP:
    取代整个页面
            "Resource=0",            //URL
    是否为一个资源  0:不是

                                                         1:

            "RecContentType=text/html", //
    录制过程中,响应报头内容格式
            "Referer=",                 //
    提交网页的URL
            "Snapshot=t1.inf",          //
    快照文件名

            "Mode=HTML",                //
    录制水平: HTML or HTTP.

    HTML level:指导VuGen录制直观的HTML动作,录制web_url,web_link,web_image。返回的是HTML页面,而不是脚本和程序。
    HTTP level:
    指导VuGen录制全部的服务器响应。不产生web_link,web_image,web_submit_form。比HTML高级,但当读脚本时不是很直观。
            EXTRARES,                   //
    参数表划分标志(下个标志是一个资源特征表)
           "Url=/dy.css", "Referer=http://www.seventest.net/index.htm", ENDITEM,     //
    资源结束志
       
           "Url=/images/bg_03.gif", "Referer=http://www.seventest.net/index.htm", ENDITEM, 
           "Url=/images/logo-end%2020GAI.swf","Referer=http://www.seventest.net/index.htm", ENDITEM,
            "Url=/images/2.swf", "Referer=http://www.seventest.net/index.htm", ENDITEM,
            LAST);                      //
    特征表结束标志

    2、下载一个游戏
    web_url("Games",
           "URL=ftp://joe:secret@mygames.com/games/archive/loderunner.exe",
           "FtpAscii=1",         //1:
    ASCII模式执行FTP传输
                                            //0:
    二进制模式
           LAST);

    3、百度搜索科学
    Action()
    {
        //
    打开首页

     web_add_cookie ("BAIDUID=AAFDECDD16EF55636CA63DC64381BBEC:FG=1; DOMAIN=www.baidu.com");

    web_add_cookie("BDSTAT=7e00ef72b41d6156ecc574f4a7efce1b9d16fdfaaf51f3debd8f8c5497eef01f3a292df5e2fe587d;DOMAIN=www.baidu.com");

                                 //网络接口的对象表达式,经常用在JavaVB.

                                //name=VALUE;必须
                                 //domain=DOMAIN_NAME;
    必须
                                  //expires=DATE;
                                  //path=PATH; (default path is "/")
                                  //secure
                                 //The elements in the Cookie parameter are the same as the elements in the
                                 //Set–Cookie HTTP Response Header.

     web_url("www.baidu.com",
      "URL=http://www.baidu.com/",  
      "TargetFrame=",
      "Resource=0",
      "RecContentType=text/html",
      "Referer=",
      "Snapshot=t1.inf",
      "Mode=HTML",
      EXTRARES,
      "Url=/favicon.ico", "Referer=", ENDITEM,
      LAST);

     web_add_cookie("BAIDUID=AAFDECDD16EF55636CA63DC64381BBEC:FG=1; DOMAIN=s.baidu.com");

     web_add_cookie("BDSTAT=7e00ef72b41d6156ecc574f4a7efce1b9d16fdfaaf51f3debd8f8c5497eef01f3a292df5e2fe587d;

    DOMAIN=s.baidu.com");

     lr_think_time(13);
       //
    搜索科学

     web_submit_data("s",         //
    提交数据

      "Action=http://www.baidu.com/s",    //
    提交数据的HTTP address
      "Method=GET",
      "EncType=",                       //
    编码方式

      "TargetFrame=",
      "RecContentType=text/html",
      "Referer=http://www.baidu.com/",
      "Snapshot=t2.inf",
      "Mode=HTML",               //
    录制水平
      ITEMDATA,
      "Name=wd", "Value=?", ENDITEM,
      "Name=cl", "Value=3", ENDITEM,
      EXTRARES,
      "Url=http://s.baidu.com/w.gif?path=http://www.baidu.com/s?wd=%BF%C6%D1%A7&cl=3&t=1200288916042",

    "Referer=http://www.baidu.com/s?wd=%BF%C6%D1%A7&cl=3", ENDITEM,
      LAST);

     return 0;
    }

     


  • (转)性能测试(并发负载压力)测试分析-简要篇

    2009-03-21 17:03:32

    在论坛混了多日,发现越来越多的性能测试工程师基本上都能够掌握利用测试工具来作负载压力测试,但多数人对怎样去分析工具收集到的测试结果感到无从下手,下面我就把个人工作中的体会和收集到的有关资料整理出来,希望能对大家分析测试结果有所帮助。

    分析原则:

    • 具体问题具体分析(这是由于不同的应用系统,不同的测试目的,不同的性能关注点)

    • 查找瓶颈时按以下顺序,由易到难。

        服务器硬件瓶颈-〉网络瓶颈(对局域网,可以不考虑)-〉服务器操作系统瓶颈(参数配置)-〉中间件瓶颈(参数配置,数据库,web服务器等)-〉应用瓶颈(SQL语句、数据库设计、业务逻辑、算法等)

        注:以上过程并不是每个分析中都需要的,要根据测试目的和要求来确定分析的深度。对一些要求低的,我们分析到应用系统在将来大的负载压力(并发用户数、数据量)下,系统的硬件瓶颈在哪儿就够了。

    • 分段排除法 很有效

    分析的信息来源:

    •1 根据场景运行过程中的错误提示信息

    •2 根据测试结果收集到的监控指标数据

    一.错误提示分析

    分析实例:

    1 •Error: Failed to connect to server “10.10.10.30:8080″: [10060] Connection

    •Error: timed out Error: Server “10.10.10.30″ has shut down the connection prematurely

    分析:

    •A、应用服务死掉。

    (小用户时:程序上的问题。程序上处理数据库的问题)

    •B、应用服务没有死

    (应用服务参数设置问题)

        例:在许多客户端连接Weblogic应用服务器被拒绝,而在服务器端没有错误显示,则有可能是Weblogic中的server元素的AcceptBacklog属性值设得过低。如果连接时收到connection refused消息,说明应提高该值,每次增加25%

    •C、数据库的连接

    (1、在应用服务的性能参数可能太小了 2、数据库启动的最大连接数(跟硬件的内存有关))

    2 Error: Page download timeout (120 seconds) has expired

    分析:可能是以下原因造成

    •A、应用服务参数设置太大导致服务器的瓶颈

    •B、页面中图片太多

    •C、在程序处理表的时候检查字段太大多

    二.监控指标数据分析

    1.最大并发用户数:

    应用系统在当前环境(硬件环境、网络环境、软件环境(参数配置))下能承受的最大并发用户数。

        在方案运行中,如果出现了大于3个用户的业务操作失败,或出现了服务器shutdown的情况,则说明在当前环境下,系统承受不了当前并发用户的负载压力,那么最大并发用户数就是前一个没有出现这种现象的并发用户数。

        如果测得的最大并发用户数到达了性能要求,且各服务器资源情况良好,业务操作响应时间也达到了用户要求,那么OK。否则,再根据各服务器的资源情况和业务操作响应时间进一步分析原因所在。

    2.业务操作响应时间:

        • 分析方案运行情况应从平均事务响应时间图和事务性能摘要图开始。使用“事务性能摘要”图,可以确定在方案执行期间响应时间过长的事务。

    • 细分事务并分析每个页面组件的性能。查看过长的事务响应时间是由哪些页面组件引起的?问题是否与网络或服务器有关?

    • 如果服务器耗时过长,请使用相应的服务器图确定有问题的服务器度量并查明服务器性能下降的原因。如果网络耗时过长,请使用“网络监视器”图确定导致性能瓶颈的网络问题

    3.服务器资源监控指标:

    内存:

    1 UNIX资源监控中指标内存页交换速率(Paging rate),如果该值偶尔走高,表明当时有线程竞争内存。如果持续很高,则内存可能是瓶颈。也可能是内存访问命中率低。

    2 Windows资源监控中,如果Process\Private Bytes计数器和Process\Working Set计数器的值在长时间内持续升高,同时Memory\Available bytes计数器的值持续降低,则很可能存在内存泄漏。

    内存资源成为系统性能的瓶颈的征兆:

    很高的换页率(high pageout rate);

    进程进入不活动状态;

    交换区所有磁盘的活动次数可高;

    可高的全局系统CPU利用率; 

    内存不够出错(out of memory errors)

    处理器:

    1 UNIX资源监控(Windows操作系统同理)中指标CPU占用率(CPU utilization),如果该值持续超过95%,表明瓶颈是CPU。可以考虑增加一个处理器或换一个更快的处理器。如果服务器专用于SQL Server,可接受的最大上限是80-85% 

    合理使用的范围在60%至70%。

    2 Windows资源监控中,如果System\Processor Queue Length大于2,而处理器利用率(Processor Time)一直很低,则存在着处理器阻塞。

    CPU资源成为系统性能的瓶颈的征兆: 

    很慢的响应时间(slow response time) 

    CPU空闲时间为零(zero percent idle CPU) 

    过高的用户占用CPU时间(high percent user CPU) 

    过高的系统占用CPU时间(high percent system CPU) 

    长时间的有很长的运行进程队列(large run queue size sustained over time)

    磁盘I/O:

    1 UNIX资源监控(Windows操作系统同理)中指标磁盘交换率(Disk rate),如果该参数值一直很高,表明I/O有问题。可考虑更换更快的硬盘系统。

    2 Windows资源监控中,如果 Disk Time和Avg.Disk Queue Length的值很高,而Page Reads/sec页面读取操作速率很低,则可能存在磁盘瓶径。

    I/O资源成为系统性能的瓶颈的征兆 :

    过高的磁盘利用率(high disk utilization) 

    太长的磁盘等待队列(large disk queue length) 

    等待磁盘I/O的时间所占的百分率太高(large percentage of time waiting for disk I/O) 

    太高的物理I/O速率:large physical I/O rate(not sufficient in itself) 

    过低的缓存命中率(low buffer cache hit ratio(not sufficient in itself)) 

    太长的运行进程队列,但CPU却空闲(large run queue with idle CPU)

    4.数据库服务器:

    SQL Server数据库:

    1 SQLServer资源监控中指标缓存点击率(Cache Hit Ratio),该值越高越好。如果持续低于80%,应考虑增加内存。

    2 如果Full Scans/sec(全表扫描/秒)计数器显示的值比1或2高,则应分析你的查询以确定是否确实需要全表扫描,以及SQL查询是否可以被优化。 

    3 Number of Deadlocks/sec(死锁的数量/秒):死锁对应用程序的可伸缩性非常有害,并且会导致恶劣的用户体验。该计数器的值必须为0。

    4 Lock Requests/sec(锁请求/秒),通过优化查询来减少读取次数,可以减少该计数器的值。

    Oracle数据库:

    1 如果自由内存接近于0而且库快存或数据字典快存的命中率小于0.90,那么需要增加SHARED_POOL_SIZE的大小。

    快存(共享SQL区)和数据字典快存的命中率: 

    select(sum(pins-reloads))/sum(pins) from v$librarycache; 

    select(sum(gets-getmisses))/sum(gets) from v$rowcache; 

    自由内存: select * from v$sgastat where name=’free memory’; 

    2 如果数据的缓存命中率小于0.90,那么需要加大DB_BLOCK_BUFFERS参数的值(单位:块)。

    缓冲区高速缓存命中率:

    select name,value from v$sysstat where name in (’db block gets’,

    ‘consistent gets’,'physical reads’) ;

    Hit Ratio = 1-(physical reads / ( db block gets + consistent gets))

    3 如果日志缓冲区申请的值较大,则应加大LOG_BUFFER参数的值。

    日志缓冲区的申请情况 :

    select name,value from v$sysstat where name = ‘redo log space requests’ ;

    4 如果内存排序命中率小于0.95,则应加大SORT_AREA_SIZE以避免磁盘排序 。

    内存排序命中率 :

    select round((100*b.value)/decode((a.value+b.value), 0, 1, (a.value+b.value)), 2)from v$sysstat a, v$sysstat b where a.name=’sorts (disk)’ and b.name=’sorts (memory)’

    注:上述SQL Server和Oracle数据库分析,只是一些简单、基本的分析,特别是Oracle数据库的分析和优化,是一门专门的技术,进一步的分析可查相关资料。

  • (转)LoadRunner性能测试指标分析

    2009-03-21 16:56:57

    LoadRunner性能测试指标

    Object

    Counters

    Descrīption

    Reference value

    Memory

    Available Mbytes

    可用物理内存数.如果Available Mbytes的值很小(4 MB或更小),则说明计算机上总的内存可能不足,或某程序没有释放内存。

    4 MB或更小,至少要有10%的物理内存值

    Page/sec

    (Input/Out)

    为了解析硬页错误,从磁盘取出或写入的页数。一般如果Page/sec持续高于几百,那么您应该进一步研究页交换活动。有可能需要增加内存,以减少换页的需求(你可以把这个数字乘以4k就得到由此引起的硬盘数据流量)。Pages/sec的值很大不一定表明内存有问题,而可能是运行使用内存映射文件的程序所致。

    推荐00-20

    如果服务器没有足够的内存处理其工作负荷,此数值将一直很高。如果大于80,表示有问题(太多的读写数据操作要访问磁盘,可考虑增加内存或优化读写数据的算法)

    该系列计数器的值比较低说明响应请求比较快, 否则可能是服务器系统内存短缺引起(也可能是缓存太大, 导致系统内存太少)。

     

     

    >5越低越好

    Page Fault

    处理器每秒处理的错误页(包括软/硬错误)。

    当处理器向内存指定的位置请求一页(可能是数据或代码)出现错误时,这就构成一个Page Fault。如果该页在内存的其他位置,该错误被称为软错误(用Transition Fault/sec记数器衡量);如果该页必须从硬盘上重新读取时,被称为硬错误。许多处理器可以在有大量软错误的情况下继续操作。但是,硬错误可以导致明显的拖延。

    Page Input/sec

    为了解决硬错误页,从磁盘上读取的页数。

    Page Output/sec

     

    Page reads/sec

    为了解决硬错误页,从磁盘上读取的次数。解析对内存的引用,必须读取页文件的次数。阈值为>5.越低越好。大数值表示磁盘读而不是缓存读。

    Cache Bytes

    文件系统缓存,默认情况下为50%的可用物理内存。如IIS5.0运行内存不够时,它会自动整理缓存。需要关注该计数器的趋势变化

     

    内存泄露

    如果您怀疑有内存泄露,请监视Memory\\ Available BytesMemory\\ Committed Bytes,以观察内存行为,并监视您认为可能在泄露内存的进程的Process\\Private BytesProcess\\Working SetProcess\\Handle Count。如果您怀疑是内核模式进程导致了泄露,则还应该监视Memory\\Pool Nonpaged BytesMemory\\ Pool Nonpaged AllocsProcess(process_name)\\ Pool Nonpaged Bytes

     

    Process

    Page Faults/sec

    将进程产生的页故障与系统产生的相比较,以判断这个进程对系统页故障产生的影响。

     

    Private Bytes

    此进程所分配的无法与其它进程共享的当前字节数量。如果系统性能随着时间而降低,则此计数器可以是内存泄漏的最佳指示器。

     

    Work set

    处理线程最近使用的内存页,反映了每一个进程使用的内存页的数量。如果服务器有足够的空闲内存,页就会被留在工作集中,当自由内存少于一个特定的阈值时,页就会被清除出工作集。

     

    Processor

    % Processor Time

    被消耗的处理器时间数量.如果服务器专用于sql server可接受的最大上限是80% -85%.也就是常见的CPU使用率.

     

    ProcessorQueue Length

    判断CPU瓶颈,如果processor queue length显示的队列长度保持不变(>=2)并且处理器的利用率%Processor time超过90%,那么很可能存在处理器瓶颈.如果发现processor queue length显示的队列长度超过2,而处理器的利用率却一直很低,或许更应该去解决处理器阻塞问题,这里处理器一般不是瓶颈.

     

    Physical

    Disk

    %DiskTime

    指所选磁盘驱动器忙于为读或写入请求提供服务所用的时间的百分比。

    正常值<10,此值过大表示耗费太多时间来访问磁盘,可考虑增加内存、更换更快的硬盘、优化读写数据的算法。若数值持续超过80 (此时处理器及网络连接并没有饱和),则可能是内存泄漏。

     

    CurrentDiskQueueLength

    读取和写入请求(为所选磁盘在实例间隔中列队的)的平均数。(磁盘数1.5-2)

     

    Avg.Disk Queue

    Length

    Avg.Disk Read

    QueueLength

    Avg.Disk Write

    QueueLength

    Disk Read/sec

    Disk Write/sec

    读取和写入请求(为所选磁盘在实例间隔中列队的)的平均数。

    磁盘瓶颈判断公式:

    每磁盘的I/O=(读次数+4*写次数))/磁盘个数。

    如果计算出来的每磁盘的I/O数大于磁盘的处理能力,那么磁盘存在瓶颈。

    Avg.DiskQueue Length正常值<0.5,此值过大表示磁盘IO太慢,要更换更快的硬盘。

     

     

  • (转)LoadRunner常用函数

    2009-03-21 16:53:26

      LoadRunner常用函数......

    1.        Intweb_reg_save_param("参数名","LB=左边界","RB=右边界",LAST);/注册函数,在参数值出现的前面使用,注册成功时返回值为0,注册失败时返回值为1。左右边界需根据TreeView里相关步骤的SeverResponse代码来确定。用以上函数能获取第一个符合条件的数值。

    2.        web_reg_save_param("参数名”,"LB=左边界”,"RB=右边界","Ord=All",LAST);/当参数有多个值时,加上"Ord=All”后可获取所有的数值。注册成功后,{参数名_count}表示取得的数值个数,{参数名_1}为第一个数值,{参数名_2}为第二个数值。

    3.        lr_save_string(“字符串变量”,"参数名")/将字符变量里的值传递给指定参数。通过该函数来改变DataFile类型参数的数值。

    4.        lr_eval_string("{参数名}")/取得参数的数值。可取得已注册参数或DataFile类型参数的数值。eval就是evaluation(估价,评价,赋值)的缩写。

    5.        int sprintf(char * string , const char*format_string[,args]);/字符串赋值函数

    Action()

    {

    int index=56;

    charfilename[64],*suffix="txt";

    sprintf(filename,"log_%d.%s",index,suffix);

    lr_output_message("Thenewfilenameis%s",filename);

    return 0;

    }

    Output:Thenewfilenameislog_56.txt

    6.        char*strcat(char*to,constchar*from);/将一字符串追加到另一字符串后面

    7.        web_find("find_time","What=2006-03-0118:21:16.882",LAST);/增加检查点,检查“2006-03-0118:21:16.882”这个字符串是否出现在当前页面上。find_time为自己任意输入的检查点名称。

    8.      事务函数

    lr_end_sub_transaction/标记子事务的结束以便进行性能分析

    lr_end_transaction/标记LoadRunner事务的结束

    lr_end_transaction_instance/标记事务实例的结束以便进行性能分析

    lr_fail_trans_with_error/将打开事务的状态设置为LR_FAIL并发送错误消息

    lr_get_trans_instance_duration/获取事务实例的持续时间(由它的句柄指定)

    lr_get_trans_instance_wasted_time/获取事务实例浪费的时间(由它的句柄指定)

    lr_get_transaction_duration/获取事务的持续时间(按事务的名称)

    lr_get_transaction_think_time/获取事务的思考时间(按事务的名称)

    lr_get_transaction_wasted_time/获取事务浪费的时间(按事务的名称)

    lr_resume_transaction/继续收集事务数据以便进行性能分析

    lr_resume_transaction_instance/继续收集事务实例数据以便进行性能分析

    lr_set_transaction_instance_status/设置事务实例的状态

    lr_set_transaction_status/设置打开事务的状态

    lr_set_transaction_status_by_name/设置事务的状态

    lr_start_sub_transaction/标记子事务的开始

    lr_start_transaction/标记事务的开始

    lr_start_transaction_instance/启动嵌套事务(由它的父事务的句柄指定)

    lr_stop_transaction/停止事务数据的收集

    lr_stop_transaction_instance/停止事务(由它的句柄指定)数据的收集

    lr_wasted_time/消除所有打开事务浪费的时间

    lr_end_sub_transaction/标记子事务的结束以便进行性能分析

    r_end_transaction/标记LoadRunner事务的结束

    lr_end_transaction_instance/标记事务实例的结束以便进行性能分析

    lr_fail_trans_with_error/将打开事务的状态设置为LR_FAIL并

     

    9.     命令行分析函数

    lr_get_attrib_double/检索脚本命令行中使用的double类型变量

    lr_get_attrib_long/检索脚本命令行中使用的long类型变量

    lr_get_attrib_string/检索脚本命令行中使用的字符串

    10. 信息性函数

    lr_user_data_point/记录用户定义的数据示例

    lr_whoami/将有关Vuser脚本的信息返回给Vuser脚本

    lr_get_host_name/返回执行Vuser脚本的主机名

    lr_get_master_host_name/返回运行LoadRunnerController的计算机名

    11. 字符串函数

    lr_eval_string/用参数的当前值替换参数

    lr_save_string/将以NULL结尾的字符串保存到参数中

    lr_save_var/将变长字符串保存到参数中

    lr_save_datetime/将当前日期和时间保存到参数中

    lr_advance_param/前进到下一个可用参数

    lr_decrypt/解密已编码的字符串

    lr_eval_string_ext/检索指向包含参数数据的缓冲区的指针

    lr_eval_string_ext_free/释放由lr_eval_string_ext分配的指针

    lr_save_searched_string/在缓冲区中搜索字符串实例,并相对于该字符串实例,该缓冲区的一部分保存到参数中

    12. 消息函数

    lr_debug_message/将调试消息发送到输出窗口

    lr_error_message/将错误消息发送到输出窗口

    lr_get_debug_message/检索当前的消息类

    lr_log_message/将输出消息直接发送到output.txt文件,此文件位于Vuser脚本目录中。该函数有助于防止输出消息干扰TCP/IP通信。

    lr_output_message/将消息发送到输出窗口

    lr_set_debug_message/为输出消息设置消息类

    lr_vuser_status_message/生成格式化输出并将其打印到ControllerVuser状态区域。

    lr_message/将消息发送到Vuser日志和输出窗口

    13. 操作函数

    web_custom_request允许您使用HTTP支持的任何方法来创建自定义HTTP请求
    web_image在定义的图像上模拟鼠标单击
    web_link在定义的文本链接上模拟鼠标单击
    web_submit_data执行“无条件”或“无上下文”的表单
    web_submit_form模拟表单的提交
    web_url加载由“URL”属性指定的URL

    14. 身份验证函数

    身份验证函数web_set_certificate使Vuser使用在InternetExplorer注册表中列出的特定证书
    身份验证函数web_set_certificate_ex指定证书和密钥文件的位置和格式信息
    身份验证函数web_set_user指定Web服务器的登录字符串和密码,用于Web服务器上已验证用户身份的区域

    15. 缓存函数

    缓存函数web_cache_cleanup清除缓存模拟程序的内容

    16. 检查函数

    检查函数web_find在HTML页内搜索指定的文本字符串
    检查函数web_global_verification在所有后面的HTTP请求中搜索文本字符串
    检查函数web_image_check验证指定的图像是否存在于HTML页内
    检查函数web_reg_find在后面的HTTP请求中注册对HTML源或原始缓冲区中文本字符串的搜索

    17. 连接定义函数

    连接定义函数web_disable_keep_alive禁用Keep-AliveHTTP连接
    连接定义函数web_enable_keep_alive启用Keep-AliveHTTP连接
    连接定义函数web_set_connections_limit设置Vuser在运行脚本时可以同时打开连接的最大数目

    18. 并发组

    web_concurrent_end标记并发组的结束
    web_concurrent_start标记并发组的开始

    19. cook函数

    web_add_cookie添加新的Cookie或修改现有的Cookie
    web_cleanup_cookies删除当前由Vuser存储的所有Cookie
    web_remove_cookie删除指定的Cookie

    20. 关联函数

    web_create_html_param将HTML页上的动态信息保存到参数中。(LR6.5及更低版本)
    web_create_html_param_ex基于包含在HTML页内的动态信息创建参数(使用嵌入边界)(LR6.5及更低版本)。
    关联函数

     
  • (转)Loadrunner message函数详细分析

    2009-03-21 16:52:30

    Loadrunner提供了若干message函数,以在脚本回放中和脚本运行中,对外输入信息,主要的函数有:
    【lr_message】
     int lr_message (const char *format, exp1, exp2,...expn.);
     中文解释:lr_message函数将信息发送到日志文件和输入窗口。在VuGen中运行时,输入文件为output.txt。

    【lr_log_message】
     int lr_log_message (const char *format, exp1, exp2,...expn.);
     中文解释:lr_log_message函数将消息发送到Vuser或代理日志文件(取决于应用程序),而不是发送到输出窗口。通过向日志文件
        发送错误消息或其他信息性消息,可以将该函数用于调试。

    【lr_error_message】
     int lr_error_message (const char *format, exp1, exp2,...expn. );
     中文解释:lr_error_message函数将错误消息发送到输出窗口和Vuser日志文件。要发送不是特定错误消息的特殊通知,请使用lr_output_message。

    【lr_output_message】
     int lr_output_message (const char *format, exp1, exp2,...expn.);
     中文解释:lr_output_message函数将带有脚本部分的行号的消息发送到输出窗口和日志文件。

    【lr_vuser_status_message】
     int lr_vuser_status_message (const char *format);
     中文解释:lr_vuser_status_message函数向控制器或优化模块控制台的vuser窗口的“状态”区域发送字符串。它还将该字符串发送
        到vuser日志。从VuGen运行时,消息被发送到output.txt。

    下面大家看例子:
    Action()
    {
     int i,j,k;
     char *message;
     j = k = 1000;

     message = "信息";
     lr_message("****************输出区域开始*****************");
     lr_message("   lr_message   %s:十进制=%d,八进制=%o,十六进制=0x%x",message,j,j,j);
     lr_log_message("   lr_log_message   %s:十进制=%d,八进制=%o,十六进制=0x%x",message,j,j,j);
     lr_error_message("   lr_error_message   %s:十进制=%d,八进制=%o,十六进制=0x%x",message,j,j,j);
     lr_output_message("  lr_output_message   %s:十进制=%d,八进制=%o,十六进制=0x%x",message,j,j,j);
     lr_message("****************输出区域结束*****************");
     for (i=1;i<6;i++)
     {
      k += 1000;
      lr_think_time (5);
      lr_vuser_status_message("第%d次:%s,十进制=%d,八进制=%o,十六进制=0x%x",i,message,k,k,k);
     }
     return 0;
    }
    例子说明:
    1、message系列的函数参数格式和c语言中的printf格式是完全相同的。
    2、格式化输入标志符号"%",想必大家也比较熟悉。其中%d是十进制,%o是八进制,%x是十六进制,%s是字符;还有%g、%u、%c等,自己去查。
    3、回放这个脚本后,进入脚本根目录查看mdrv.log,所有输出都可以在这里找到。
    4、lr_error_message回放日志中显示的是红色的字体,且显示语句所在行号;同时,如果脚本在controllor中运行时,会生成一个error信息。
    5、lr_vuser_status_message会在controllor的vuser list的status列中显示,controllor每5秒刷新一次。
    6、当然,也支持转义字符的使用,列表如下:
    \a 铃声(警告)
    \b Backspace 键
    \f 换页
    \n 换行
    \r 回车
    \t 水平制表符
    \v 垂直制表符
    \' 单引号标记
    \" 双引号标记
    \\ 反斜杠
    \? 文本问号
    \ooo ASCII 字符 - 八进制
    支持的转换字符有:
    %a ASCII 表示形式
    %BX 大端(网络顺序)十六进制
    %BO 大端(网络顺序)八进制
    %BD 大端(网络顺序)十进制
    %LX 小端十六进制
    %LO 小端八进制
    %LD 小端十进制

    ==============================================================

    此外,loadrunner还提供了在脚本中控制runtime-setting的log设置的函数。
    【lr_debug_message函数组】
    int lr_debug_message (unsigned int message_level, const char *format, ... );
     中文解释:lr_debug_message函数在指定的消息级别处于活动状态时发送一条调试信息。如果指定的消息级别未出于活动状态,则不
        发送消息。您可以从用户界面或者使用lr_set_debug_message, 将处于活动状态的消息级别设置为MSG_CLASS_BRIEF_LOG
        或MSG_CLASSS_EXTENDED_LOG。要确定当前级别,请使用lr_get_debug_message。

    unsigned int lr_get_debug_message ( );
     中文解释:lr_get_debug_message函数返回当前的日志运行时设置。该设置确定发送到输出端的信息。日志设置是使用运行时设置对
        话框或通过使用lr_set_debug_message函数指定的。

    int lr_set_debug_message (unsigned int message_level, unsigned int on_off);
     中文解释:lr_set_debug_message函数设置脚本执行的调试消息级别message_lvl。通过设置消息级别,可以确定发送哪些信息。 启
        动设置的方法是将LR_SWITCH_ON作为on_off传递,禁用设置的方法是传递LR_SWITCH_OFF。

    参数message_level说明:
    【日志级别】====【C语言标志】====【值】====【Runtime-setting - Log操作】 
    【Disabled】====【LR_MSG_CLASS_DISABLE_LOG】====【0】====【不勾选Enable logging】 
    【Brief】====【LR_MSG_CLASS_BRIEF_LOG】====【1】====【勾选Standard log】
    【Extended Log】====【LR_MSG_CLASS_EXTENDED_LOG】====【16】====【勾选Extended log】
    【Result Data】====【LR_MSG_CLASS_RESULT_DATA】====【2】====【勾选Data returned by server】
    【Parameter Substitution】====【LR_MSG_CLASS_PARAMETERS】====【4】====【勾选Parameter substitution】 
    【Full Run-Time Trace】====【LR_MSG_CLASS_FULL_TRACE】====【8】====【 勾选 Advanced trace】
    【Only on error】====【LR_MSG_CLASS_JIT_LOG_ON_ERROR】====【512】====【勾选send messages only when an error occurs】 

    参数on_off说明:
    【LR_SWITCH_ON】启用设置
    【LR_SWITCH_OFF】禁用设置


    看下面的小例子:
    Action()
    {
     int log_leavl;
     log_leavl = lr_get_debug_message();
     lr_error_message ("当前是:%d",log_leavl);
     return 0;
    }
    当我设置只有错误信息(error)打印【勾选send messages only when an error occurs】,例子运行结果是:当前是:513;
    为什么不是512呢,我发现我实际选择的是【Enable logging + send messages only when an error occurs】,按上面的
    参数说明,就是【1+512】,也就是513了;因此:
    lr_get_debug_message返回的int数其实是所有勾选操作的代表值相加!


    再看下面设置的例子:

    Action()
    {
    //设置runtime-setting的日志选项【不勾选Enable logging】
     char *a;
     a = "ABC";
     lr_set_debug_message (LR_MSG_CLASS_EXTENDED_LOG |LR_MSG_CLASS_PARAMETERS,LR_SWITCH_ON);
     //打开Runtime-setting Log 的Parameter substitution设置
     lr_debug_message(LR_MSG_CLASS_PARAMETERS,"打开参数保存的系统日志");
     lr_save_string("aa",a);
     lr_debug_message(LR_MSG_CLASS_PARAMETERS,"关闭参数保存的系统日志");
     lr_set_debug_message (LR_MSG_CLASS_EXTENDED_LOG |LR_MSG_CLASS_PARAMETERS,LR_SWITCH_OFF);
     //关闭Runtime-setting Log 的Parameter substitution设置

     return 0;
    }
    因为设置了runtime-setting不打印任何日志,所以正常运行脚本应该没有任何日志输出;
    但是使用lr_set_debug_message函数打开了日志的设置(输出保存参数操作的日志)
    因此脚本运行到lr_save_string("aa",a)时,就输出了日志如下:

    打开参数保存的系统日志
    Action.c(7): Notify: Saving Parameter "ABC = aa"
    关闭参数保存的系统日志

  • (转)Loadrunner中参数设置详细分析

    2009-03-21 16:46:37

    Loadrunner中参数设置详细分析(一)

    相信对大家会有用的,这个版本是基于7.8的。
    做负载或者压力测试时,很多人选择使用了Loadrunner测试工具。该工具的基本流程是先将用户的实际操作录制成脚本,然后产生数千个虚拟用户运行脚本(虚拟用户可以分布在局域网中不同的PC机上),最后生成相关的报告以及分析图。但是在录制脚本的过程中会遇到很多实际的问题,比如不同的用户有不同的使用数据,这就牵涉到参数的设置问题。本文就Loadrunner中参数的设置进行说明,希望对大家有所帮助。
       在录制程序运行的过程中,VuGen(脚本生成器) 自动生成了包含录制过程中实际用到的数值的脚本。如果你企图在录制的脚本中使用不同的数值执行脚本的活动(如查询、提交等等),那么你必须用参数值取代录制的数值。这个过程称为参数化脚本。
       本文主要包括如下内容:理解参数的局限性、建立参数、定义参数的属性、理解参数的类型、为局部数据类型设置参数的属性、为数据文件设置参数的属性、从已经存在的数据库中引入数据。
       除了GUI,以下的内容适合于各种类型的用户脚本。
    一、关于参数的定义
       在你录制程序运行的过程中,脚本生成器自动生成由函数组成的用户脚本。函数中参数的值就是在录制过程中输入的实际值。
       例如,你录制了一个Web应用程序的脚本。脚本生成器生成了一个声明,该声明搜索名称为“UNIX”的图书的数据库。当你用多个虚拟用户和迭代回放脚本时,也许你不想重复使用相同的值“UNIX”。那么,你就可以用参数来取代这个常量。结果就是你可以用指定的数据源的数值来取代参数值。数据源可以是一个文件,也可以是内部产生的变量。
       用参数表示用户的脚本有两个优点:
    ① 可以使脚本的长度变短。
    ② 可以使用不同的数值来测试你的脚本。例如,如果你企图搜索不同名称的图书,你仅仅需要写提交函数一次。在回放的过程中,你可以使用不同的参数值,而不只搜索一个特定名称的值。
       参数化包含以下两项任务:
    ① 在脚本中用参数取代常量值。
    ② 设置参数的属性以及数据源。
       参数化仅可以用于一个函数中的参量。你不能用参数表示非函数参数的字符串。另外,不是所有的函数都可以参数化的。

     

    二、参数的创建
       可以指定名称和类型来创建参数。不存在对脚本中参数个数的限制。在Web程序的用户脚本中,你可以使用如下过程在基于文本的脚本视图中创建参数。或者,也可以在基于图标的树形视图中创建参数。
       在基于文本的脚本视图中创建一个参数:
    1、 将光标定位在要参数化的字符上,点击右键。打开弹出菜单。
    2、 在弹出菜单中,选择“Replace with a Parameter”。选择或者创建参数的对话框弹出。
    3、 在“Parameter name”中输入参数的名称,或者选择一个在参数列表中已经存在的参数。
    4、 在“Parameter type”下拉列表中选择参数类型。
    5、 点击“OK”,关闭该对话框。脚本生成器便会用参数中的值来取代脚本中被参数化的字符,参数用一对“{}”括住。
       注意:在参数化CORBA或者General-Java 用户脚本的时候,必须参数化整个字符串,而不是其中的部分。另外注意:除了Web或者WAP,缺省的参数括号对于任何脚本都是 “{}”。你可以在“General Options”对话框中的“Parameterization”标签(Tools>General Options)中定义参数括号种类。
    6、 用同样的参数替换字符的其余情况,选中参数,点击右键,弹出菜单。从弹出的菜单中,选择“Replace More Occurrences”。搜索和替换对话框弹出。“Find What”中显示了你企图替换的值。“Replace With”中显示了括号中参数的名称。选择适当的检验框来匹配整个字符或者大小写。如果要搜索规则的表达式(.,!,?等等),选中“Regular Expression”检验框,然后点击“Replace”或者“Replace All”。
       注意:小心使用“Replace All”,尤其替换数字字符串的时候。脚本生成器将会替换字符出现的所有情况。
    7、 如果想用以前定义过的参数来替换常量字符串的话,选中该字符串,点击右键,然后选择“Use Existing Parameter”,子菜单“Use Existing Parameters”弹出。从子菜单“Use Existing Parameters”选择参数,或者用“Select from Parameter List”来打开参数列表对话框。
       注意:如果用以前定义过的参数来替换常量字符串的话,那么,使用“Parameter List”非常方便。同时,还可以查看和修改该参数的属性。
    8、 对于已经用参数替换过的地方,如果想取回原来的值,那么,就在参数上点击右键,然后选择“Restore Original value”。
       在Web用户脚本的树形视图中创建参数:
    1、将光标定位在企图参数化的地方,点击右键,从弹出的菜单中选择“Properties”。则相关的属性对话框打开。
    2、点击在要参数化的参量的旁边的“ABC”形状的图标。“Select or Create Parameter”对话框打开。
    3、在“Parameter name”中输入参数的名称,或者从列表中选择一个已经存在的参数。
    4、在“Parameter type”中输入参数的类型。
    5、点击“OK”关闭该对话框。用户脚本生成器会用参数来替换最初的字符串常量,并用一个表格形状的图标替换“ABC”形状的图标。
    6、要恢复参数化以前的值,点击图标,然后从弹出的菜单中选择“Undo Parameter”,则以前的值便会重现。

     

    三、定义参数的属性
       创建参数完成后,就可以定义其属性了。参数的属性定义就是定义在脚本执行过程中,参数使用的数据源。在Web用户脚本中,你既可以在基于文本的脚本视图中定义参数属性,也可以在基于图标的树形视图中定义参数属性。下面的过程将教你如何在基于本文的脚本视图中定义参数属性。
       在基于文本的脚本视图中定义参数属性步骤:
    1、 在参数上点击右键,有菜单弹出。
    2、 在弹出的菜单中,选择“Parameter Properties”。参数属性对话框打开,显示和当前参数类型相关的属性。
    3、 输入参数的属性值。
    4、 点击“Close”关闭参数属性对话框。
        在Web用户脚本的树形视图中定义参数的属性:
    1、 将关标定位在参数上,然后点击右键,选择“Properties”。属性对话框打开。
    2、 点击要定义属性的参数旁边的表格形状按钮,点击右键,选择“Parameter Properties”。参数属性对话框打开,和参数类型相关的属性显示出来。
    3、 输入参数的属性。
    4、 点击“Close”关闭参数属性对话框。
       使用参数列表:
      使用参数列表可以在任意时刻查看所有的参数,创建新的参数、删除参数,或者修改已经存在参数的属性。
    1、 点击参数列表按钮或者用“Vuser>Parameter List”。参数列表对话框打开。
    2、 要创建新的参数,点击“New”按钮。新的参数则被添加在参数树中,该参数有一个临时的名字,你可以给它重新命名,然后回车。设置参数的类型和属性,点击“OK”,关闭参数列表对话框。
       注意:不要将一个参数命名为“unique”,因为这个名称是用户脚本生成器本身的。用户脚本生成器创建新的参数,但是不会自动用该参数在脚本中替换任意选中的字符串。
    3、 要删除已有的参数,那么,要先从参数树中选择该参数,点击“Delete”,然后确认你的行为即可。
    4、 要修改已有参数,那么,要先从参数树中选择该参数,然后编辑参数的类型和属性。

    四、理解参数的类型
      在你定义参数属性的时候,要指定参数值的数据源。你可以指定下列数据源类型的任何一种:
    Internal Data―― 虚拟用户内部产生的数据。
    Data Files ――存在于文件中的数据。可能是已存在的文件或者是用脚本生成器新创建的。
    User-Defined Functions―― 调用外部DLL函数生成的数据
      Internal Data包括以下几种:
    1、 Date/Time
      Date/Time用当前的日期/时间替换参数。要指定一个Date/Time格式,你可以从菜单列表中选择格式,或者指定你自己的格式。这个格式应该和你脚本中录制的Date/Time格式保持一致。
    2、 Group Name
      Group Name 用虚拟用户组名称替换参数。在创建scenario的时候,你可以指定虚拟用户组的名称。当从用户脚本生成器运行脚本的时候,虚拟用户组名称总是None。
    3、 Load Generator Name
      Load Generator Name用脚本负载生成器的名称替换参数。负载生成器是虚拟用户在运行的计算机。
    4. Iteration Number
      Iteration Number用当前的迭代数目替换参数。
    5、 Random Number
      Random Number用一个随机数替换参数。通过指定最大值和最小值来设置随机数的范围。
    6、 Unique Number
      Unique Number用一个唯一的数字来替换参数。你可以指定一个起始数字和一个块的大小。
    7、 Vuser ID
      Vuser ID用分配给虚拟用户的ID替换参数,ID是由Loadrunner的控制器在scenario运行时生成的。如果你从脚本生成器运行脚本的话,虚拟用户的ID总是-1。

    五、数据文件
      数据文件包含着脚本执行过程中虚拟用户访问的数据。局部和全局文件中都可以存储数据。可以指定现有的ASCII文件、用脚本生成器创建一个新的文件或者引入一个数据库。在参数有很多已知值的时候数据文件非常有用。数据文件中的数据是以表的形式存储的。一个文件中可以包含很多参数值。每一列包含一个参数的数据。列之间用分隔符隔开,比如说,用逗号。
      对数据文件设置参数属性
      如果使用文件作为参数的数据源,必须指定以下内容:文件的名称和位置、包含数据的列、文件格式,包括列的分隔符、更新方法。
     如果参数的类型是“File”,打开参数属性(Parameter Properties)对话框,设置文件属性如下:
    1、 在“File path”中输入文件的位置,或者点击“Browse”指定一个已有文件的位置。缺省情况下,所有新的数据文件名都是“parameter_name.dat”,注意,已有的数据文件的后缀必须是.dat。
    2、 点击“Edit”。记事本打开,里面第一行是参数的名称,第二行是参数的初始值。使用诸如逗号之类的分隔符将列隔开。对于每一新的表行开始一行新的数据。
      注意:在没有启动记事本的情况下如果想添加列,就在参数属性对话框中点击“Add Col”,那么“Add new column”对话框就会弹出。输入新列的名称,点击“OK”。脚本生成器就会添加该列到表中,并显示该列的初始值。
    3、 在“Select Column”部分,指明包含当前参数数据的列。你可以指定列名或者列号。列号是包含你所需要数据的列的索引。列名显示在每列的第一行(row 0)。
    4、 在“Column delimiter”中输入列分隔符,你可以指定逗号、空格符等等。
    5、 在“First data line”中,在脚本执行的时候选择第一行数据使用。列标题是第0行。若从列标题后面的第一行开始的话,那就在“First data line”中输入1。如果没有列标题,就输入0。
    6、 在“Select next row”中输入更新方法,以说明虚拟用户在脚本执行的过程中如何选择表中的数据。方法可以是:连续的、随机的、唯一的、或者与其它参数表的相同行。
    6.1、 顺序(Sequential):该方法顺序地给虚拟用户分配参数值。如果正在运行的虚拟用户访问数据表的时候,它会取到下一行中可用的数据。
    6.2、 随机(Random):该方法在每次迭代的时候会从数据表中取随机数
    6.3、 使用种子取随机顺序(Use Random Sequence with Seed):如果从Loadrunner的控制器来运行scenario,你可以指定一个种子数值用于随机顺序。每一个种子数值在测试执行的时候代表了一个随机数的顺序。无论你何时使用这个种子数值,在scenario中同样的数据顺序就被分配给虚拟用户。如果在测试执行的时候发现了一个问题并且企图使用同样的随机数序列来重复测试,那么,你就可以启动这个功能(可选项)。
    6.4、 唯一(Unique):Unique方法分配一个唯一的有顺序的值给每个虚拟用户的参数。
    6.5 、与以前定义的参数取同一行(Same Line As <parameter>):该方法从和以前定义过的参数中的同样的一行分配数据。你必须指定包含有该数据的列。在下拉列表中会出现定义过的所有参数列表。注意:至少其中的一个参数必须是Sequential、Random或者Unique。

    如果数据表中有三列,三个参数定义在列表中:id1,name1和title1,如下:。
    ID Name Title
    132 Kim Manager
    187 Cassie Engineer
    189 Jane VP
        对于参数id1,你可以指示虚拟用户使用Random方法,而为参数name1和title1就可以指定方法“Same Line as id1”。所以,一旦ID“132”被使用,那么,姓名(Name)“Kim”和职位(Title)“Manager”同时被使用。

    7、Updta value on数据的更新方法
    7.1、Each iteration――每次反复都要取新值
    7.2、Each occurrence――只要发现该参数就重新取值
    7.3、Once――在所有的反复中都使用同一个值
    8、When out of values超出范围:(选择数据为unique时才可用到)
    8.1、Abort Vuser――中止
    8.2、Continue in a cyclic manner――继续循环取值
    8.3、Continue with last value――取最后一个值
    9、Allocate Vuser values in the Controller在控制器中分配值:(选择数据为unique时才可用到)
    9.1、 Automatically allocate block size――自动分配
    9.2、Allocate()values for each Vuser――指定一个值

    六、从已存在的数据库中导入数据

    Loadrunner允许你利用参数化从已经存在的数据库中导入数据。可以使用下列两种方式之一:
    1、 使用Microsoft Query(要求在系统上先安装MS Query)。
    2、 指定数据库连接字符串和SQL语句。
        用户脚本生成器在从数据库中导入数据的过程中提供了一个向导。在向导中,你指明如何导入数据-通过MS Query创建查询语句或者直接书写SQL语句。在导入数据以后,以.dat为后缀并作为正规的参数文件保存。要开始导入数据库中数据的过程,在参数属性对话框中点击“Data Wizard”,则,数据库查询向导弹出。
      要创建新的查询
    1、 选择“Create new query”。如果需要MS Query的帮助,选择“Show me how to use Microsoft Query”,然后点击“Finish”。
    如果你还没有安装Microsoft Query,Loadrunner会提示你这个功能不可用。在进行之前,从Microsoft Office中安装MS Query。
    2、 在Microsoft Query中遵循以下步骤,导入期望的表和列。
    3、 在完成数据的导入后,选择“Exit and return to Virtual User Generator”,然后点击“Finish”。在参数属性对话框中数据库记录以data文件的形式显示出来。
    要在MS Query中编辑并查看数据,选择“View data or edit in Microsoft Query”。若要结束,则选择“File>Exit and return to Virtual User Generator”返回到脚本生成器。
    4、 在“Select Column”部分,指定包含当前参数数据的列可以指定列号或者列名。注意:列标题默认为第0行(row 0)。
    5、 从“Select next row”列表中选择一个更新方法来告诉虚拟用户在脚本指定的过程中如何选择表中的数据。可选项是:Sequential、Random、Unique或者Same Line As。其中每一项的含义文章前面已经讲述,就不再赘述。
    6、 如果选择“Advance row each iteration”,虚拟用户在每次迭代的时候会使用新的一行的数据而不是重复同样的数据。
      要指定数据库连接或者SQL语句
    1、 选择“Specify SQL Statement”,然后点击“Next”。
    2、 点击“Create”指定一个新的连接字符串。选择数据源的窗口弹出。
    3、 选择已有的数据源,或者点击“New”创建一个新的数据源。向导将提示你穿过创建ODBC数据源的过程。在完成后,连接字符串就会在连接字符串框中显示出来。
    4、 在SQL框中,输入或者粘贴SQL语句。
    5、 点击“Finish”继续SQL语句并导入数据。数据库记录将以data文件的形式显示在参数属性框中。
    6、 在“Select Column”部分中,指定包含当前参数数据的列。你可以指定列号或者列名。
    7、 从“Select next row”列表中选择一个更新方法来告诉虚拟用户在脚本指定的过程中如何选择表中的数据。可选项是:Sequential、Random、Unique或者Same Line As。


     

     

  • (转)学习loadrunner之一_事务

    2009-03-21 16:39:25

    Loadrunner是一款负载测试工具,它有三个核心组件分别是Virtual User GeneratorControllerAnalysisVirtual User Generator可以通过录制脚本准确的记录下来用户的每一步操作并且可以进行集合点设置、事务设置、参数化等操作从而为在Controller中执行特定的场景做准备。Controller顾名思义,它可以控制脚本的执行,通过把脚本放置在一个特定的场景中,模拟一批真实用户的操作过程,这些模拟的真实用户就叫做虚拟用户。通过这些虚拟用户可以对系统进行负载测试。Analysis应该是测试人员极为关注的一个组件,通过Controller执行完某一个场景之后,Analysis可以自动生成测试结果并通过图形的形式显示出来,测试人员只有借助这些图表才能准确分析出系统的瓶颈并且确定性能是否达到要求。

        下面介绍一下如何进行集合点、检查点以及参数化的设置:

        对于集合点、检查点的设置有两种方法,一种是在录制完脚本以后,手工在脚本中添加相关的关键字例如lr_start_transaction等,这种方法对脚本语言的理解能力要求较高。另一种是直接在录制的过程中添加集合点、检查点,这样lr就会自动把集合点、检查点的关键字添加到脚本中。

        事务:就是用户某一步或者某几步操作的集合。当我们需要通过某一步或是某几步操作从而衡量服务器的性能的时候,这时我们就把这些操作设置成一个事务,当事务开始执行的时候lr就开始计时当事务运行结束计时停止,执行事务的时间会在在最后的结果中显示出来。

        实例:登录sina网站,把点击“天气”设置成一个事务,衡量服务器处理处理该事务的性能。

        1,点击红色的录制按钮,输入URL开始录制。弹出sina的首页,点击<!--[if !vml]--><!--[endif]-->设置事物的开始位置,这时弹出事务开始对话框要求输入事务的名称,一般来讲我们都会把事务名称命名为容理解的名字,此处我们命名为“天气”

        点击OK完成事务的开始点设置。

        2,在sina页面上点击“天气”的连接,出现天气页面

        3,点击<!--[if !vml]--><!--[endif]-->设置事务的结束点,这时弹出事务结束对话框

        lr根据匹配原则已经自动把事务名字一栏填入“天气”,我们只需要选择事务的状态。状态有三种LR_AUTOLR_PASSLR_FAILLR_STOP

        LR_AUTO:事物的状态被自动设置,如果事务执行成功,状态设置为PASS,如果执行失败,状态设置为FAIL,如果由于异常中断,状态被设置成STOP.

        LR_PASS:事务如果执行成功,代码的返回状态就是PASS

        LR_FAIL:事务如果执行失败,代码的返回状态就是FAIL

        一般我们选择LR_AUTO那么我们会有疑问什么时候我们选择PASS或者是FAIL呢?

        Lr的帮助文档中有一条例子,可以很好的帮助我们理解

    lr.start_transaction("GetStocks");
    try {

    String stocks[];
    stocks = orStockServer1.getStockList();
    if (stocks.length == 0)

                  throw new Exception("No stocks returned/available");
    lr.end_transaction("GetStocks", lr.PASS);
    }

    catch (Exception e1) {

           lr.end_transaction("GetStocks", lr.FAIL);

           lr.message(" An exception occurred : " + e1.toString() );

           }

    代码说明:这时一个得到stock list的例子,程序中设置了异常检查来确保getStockList()方法返回非零的长度。

     

    同时我也进行了如下的脚本修改

    ………………

    lr_start_transaction("天气");

       lr_think_time( 3 );

       web_add_cookie("mysinal=ai_erica; DOMAIN=weather.news.sina.com.cn");

       web_add_cookie("SINAGLOBAL=221.219.31.58.924471172571904604; DOMAIN=weather.news.sina.com.cn");

    ………………

    lr_end_transaction("天气", LR_FAIL);

        在最后我把该事物的结束状态设置为FAIL,然后运行该脚本,其实该事物的运行是没有任何错误的,完全可以运行成功,只是在最后我把事务的状态手工设置为FAIL。当脚本执行完后,查看Ececution Log看到这样一条log语句:

        Action.c(297): Notify: Transaction "天气" ended with "Fail" status (Duration: 5.1436).

        那么这样做的意义是什么呢?为什么要设置事务结束状态呢?原因就是在Analysis中生成结果图表的时候我们就能看到这个名为“天气”的事务执行是失败的。如果语句是这样:

        Action.c(297): Notify: Transaction "天气" ended with "Pass" status (Duration: 5.1436).

        Analysis中生成结果图表的时候我们就能看到这个名为“天气”的事务执行是成功的。

        设置事务结束状态的用途就在这里。试想Lr为什么能自动生成结果图表?无非就是Analysis通过一些定义好的API获取执行脚本过程中的返回值,从而显示出事务执行的正确还是错误,或是显示出响应时间等信息,然后调用GUI使我们很直观的看到测试结果。

  • (转)LoadRunner脚本编程(例子)

    2009-03-21 15:37:06

    LoadRunner脚本编程

    今天想统计一下我的BLOG的访问情况,想知道那些文章被经常阅读。在BLOG的后台没找到相关功能,既然没有那就自已动手吧,要想统计就需要数据,数据只能从网页里来。从网页中取数据一个是手工取,一个是自动来取。手工取没啥兴趣,那就自动取吧,网页的格式都是有一定规律的,自动取会很方便。先打开一页,看看源代码需要取数据的点有那些特征。打开页面后找到了需要的特征,在每个标题前有一段HTML代码 “<img src=images/face/1.gif >” 在每篇文章的点击次数有特征标示 “阅读全文”,有了这两个特征就可以提取需要的数据了。

    下面是具体的LoadRunner脚本代码

    #include "as_web.h"
    int i,j; //定义变量,循环次数
    char URL1[512],COUNT[512],Name[512]; //定义变量,存储参数化名称
    Action1()
    {
       for(i=1;i<=10;i++)//当前BLOG只有10页 所以循环次数为10
       {  

           web_reg_save_param("Count","LB=阅读全文(","RB=)</a>","ORD=all",LAST);  //设定点击数参数化变量

           web_reg_save_param("Name","LB=<img src=images/face/1.gif >","RB=</a>","ORD=all",LAST);//设定标题参数化变量

           sprintf(URL1,"URL=http://www1.testage.net/blog/blog.asp?name=alanstone&page=%d",i);//准备需要访问的URL

           web_url("Link",URL1,LAST); //访问URL

           for(j=1;j<=atoi(lr_eval_string("{Count_count}"));j++) //按得到的参数化变量数量进行循环
           {

               sprintf(COUNT,"{Count_%d}",j); //准备点击次数参数化变量

               sprintf(Name,"{Name_%d}",j); //准备标题参数化变量

               lr_message("%s   %s",lr_eval_string(Name),lr_eval_string(COUNT));//打印标题和点击次数   
            }
        }
    return 0;
    }

    该脚本唯一有点难度的是需要一点C语言的基础,同时对于web_reg_save_param参数有一些了解,具体web_reg_save_param参数使用方法可以查看LR的联机文档。
  • 如何在loadrunner中做关联

    2009-03-21 15:22:10

    如何在LoadRunner脚本中做关联 (Correlation) (转贴hanxue1230)
    j%G}.z^3tLI138711当录制脚本时,VuGen会拦截client端(浏览器)与server端(网站服务器)之间的对话,并且通通记录下来,产生脚本。在VuGen的Recording Log中,您可以找到浏览器与服务器之间所有的对话,包含通讯内容、日期、时间、浏览器的请求、服务器的响应内容等等。脚本和Recording Log最大的差别在于,脚本只记录了client端要对server端所说的话,而Recording Log则是完整纪录二者的对话。
    +?dv0@[^Hz9h,Z138711
    u(p+h4Af)r2{,a;J138711当执行脚本时,您可以把VuGen想象成是一个演员,它伪装成浏览器,然后根据脚本,把当初真的浏览器所说过的话,再对网站伺服器重新说一遍,VuGen企图骗过服务器,让服务器以为它就是当初的浏览器,然后把网站内容传送给VuGen。51Testing软件测试网3k1?e8M:Y6A
    所以纪录在脚本中要跟服务器所说的话,完全与当初录制时所说的一样,是写死的(hard-coded)。这样的作法在遇到有些比较聪明的服务器时,还是会失效。这时就需要透过「关联(correlation)」的做法来让VuGen可以再次成功地骗过服务器。51Testing软件测试网l+].ZI2`Qxm{#_
    何谓关联(correlation)?51Testing软件测试网4b)tW\:U)^
    所谓的关联(correlation)就是把脚本中某些写死的(hard-coded)数据,转变成是撷取自服务器所送的、动态的、每次都不一样的数据。51Testing软件测试网z2D!@(\$k1|I
    举一个常见的例子,刚刚提到有些比较聪明的服务器,这些服务器在每个浏览器第一次跟它要数据时,都会在数据中夹带一个唯一的辨识码,接下来就会利用这个辨识码来辨识跟它要数据的是不是同一个浏览器。一般称这个辨识码为Session ID。对于每个新的交易,服务器都会产生新的Session ID给浏览器。这也就是为什么执行脚本会失败的原因,因为VuGen还是用旧的Session ID向服务器要数据,服务器会发现这个Session ID是失效的或是它根本不认识这个Session ID,当然就不会传送正确的网页数据给VuGen了。
    g&s Ws(U7K8OP5p\138711下面的图示说明了这样的情形:51Testing软件测试网UYP*Yo'B
    当录制脚本时,浏览器送出网页A的请求,服务器将网页A的内容传送给浏览器,并且夹带了一个ID=123的数据,当浏览器再送出网页B的情求时,这时就要用到ID=123的数据,服务器才会认为这是合法的请求,并且把网页B的内容送回给浏览器。51Testing软件测试网}r.U-H5M J
    在执行脚本时会发生什么状况?浏览器再送出网页B的请求时,用的还是当初录制的ID=123的数据,而不是用服务器新给的ID=456,整个脚本的执行就会失败。
    {&?6o mJVS138711
    tjujK\%Cu138711要对付这种服务器,我们必须想办法找出这个Session ID到底是什么、位于何处,然后把它撷取下来,放到某个参数中,并且取代掉脚本中有用到Session ID的部份,这样就可以成功骗过服务器,正确地完成整个交易了。
    j9VUv CZ,H H_138711哪些错误代表着我应该做关联(correlation)?
    kv5r/z`S138711假如脚本需要关联(correlation),在还没做之前是不会执行通过的,也就是说会有错误讯息发生。不过,很不幸地,并没有任何特定的错误讯息是和关联(correlation)有关系的。会出现什么错误讯息,与系统实做的错误处理机制有关。错误讯息有可能会提醒您要重新登入,但是也有可能直接就显示HTTP 404的错误讯息。
    '\)fmtA*j@'S138711要如何做关联(correlation)?51Testing软件测试网Y4Sv,h\1Ze
    关联(correlation)函数
    e*pCwN)G[ \138711关联(correlation)会用到下列的函数:51Testing软件测试网} s+Ms @
    • web_reg_save_param:这是最新版,也是最常用来做关联(correlation)的函数。
    z-A;U1d%`r1|~ ?138711语法:
    byp$d}0a138711web_reg_save_param ( “Parameter Name” , < list of Attributes >, LAST );51Testing软件测试网J/{b$L,y$A
    • web_create_html_param、web_create_html_param_ex:这二个函数主要是保留作为向前兼容的目的的。建议使用 web_reg_save_param 函数。
    v.|p%DF+mP[1d]N138711详细用法请参考使用手册。在VuGen中点选【Help】>【Function reference】>【Contexts】>【Web and Wireless Vuser Functions】>【Correlation Functions】。51Testing软件测试网 ?p{1W%S!ti
    如何找出要关联(correlation)数据
    Q*y9vI&E m138711简单的说,每一次执行时都会变动的值,就有可能需要做关联(correlation)。51Testing软件测试网&l4ZQ^l#I!rX
    VuGen提供二种方式帮助您找出需要做关联(correlation)的值:
    h3h'@5{Y&t1387111. 自动关联51Testing软件测试网O*WE j9xg$G;T`[
    2. 手动关联
    8J{ ~ot1C8hY y138711自动关联
    "f9}go/@4nY&R138711VuGen内建自动关联引擎(auto-correlation engine),可以自动找出需要关联的值,并且自动使用关联函数建立关联。
    r,t5j+V`$B f]1u;h138711自动关联提供下列二种机制:
    ZJHvj P-A;U138711• Rules Correlation:在录制过程中VuGen会根据订定的规则,实时自动找出要关联的值。规则来源有两种:
    .{;LX9U)d+WP.~138711o 内建(Built-in Correlation):
    (J!kc` i[~138711VuGen已经针对常用的一些应用系统,如AribaBuyer、BlueMartini、BroadVision、InterStage、mySAP、NetDynamics、Oracle、PeopleSoft、Siebel、SilverJRunner等,内建关联规则,这些应用系统可能会有一种以上的关联规则。您可以在【Recording Options】>【Internet Protocol】>【Correlation】中启用关联规则,则当录制这些应用系统的脚本时,VuGen会在脚本中自动建立关联。51Testing软件测试网0`$B0D,XYGK
    您也可以在【Recording Options】>【Internet Protocol】>【Correlation】检视每个关联规则的定义。51Testing软件测试网 av%u `4G"l0f
    o 使用者自订(User-defined Rules Correlation):
    V L"qZ"` |138711除了内建的关联规则之外,使用者也可以自订关联规则。您可以在【Recording Options】>【Internet Protocol】>【Correlation】建立新的关联规则。51Testing软件测试网Gq7Ich7R2c
    • Correlation Studio:有别于Rules Correlation,Correlation Studio则是在执行脚本后才会建立关联,也就是说当录制完脚本后,脚本至少须被执行过一次,Correlation Studio才会作用。Correlation Studio会尝试找出录制时与执行时,服务器响应内容的差异部分,藉以找出需要关联的数据,并建立关联。51Testing软件测试网+CG`3Bqc7\ G#z!OL$b
    Rule Correlation51Testing软件测试网{m RqG&^#k^
    请依照以下步骤使用Rule Correlation:51Testing软件测试网1W0EW(}i5hZ!g p4iy
    1. 启用auto-correlation51Testing软件测试网X#dOB qSZ [
    1. 点选VuGen的【Tools】>【Recording Options】,开启【Recording Options】对话窗口,选取【Internet Protocol】>【Correlation】,勾选【Enable correlation during recording】,以启用自动关联。51Testing软件测试网9c1V(Q#a(yn
    2. 假如录制的应用系统属于内建关联规则的系统,如AribaBuyer、BlueMartini、BroadVision、InterStage、mySAP、NetDynamics、Oracle、PeopleSoft、Siebel、SilverJRunner等,请勾选相对应的应用系统。
    T/q8| CvJu1387113. 或者也可以针对录制的应用系统加入新的关联规则,此即为使用者自订的关联规则。
    -T7wLK y:Y,@S1387114. 设定当VuGen侦测到符合关联规则的数据时,要如何处理:
    f(M rm#H#q5a138711 【Issue a pop-up message and let me decide online】:跳出一个讯息对话窗口,询问您是否要建立关联。
    TS-x4c |J{SV138711 【Perform. correlation in sceipt】:直接自动建立关联51Testing软件测试网OM$~:S)ddR
    2. 录制脚本
    2i9t7~0b8T"mu%?138711开始录制脚本,在录制过程中,当VuGen侦测到符合关联规则的数据时,会依照设定建立关联,您会在脚本中看到类似以下的脚本,此为BroadVision应用系统建立关联的例子,在脚本批注部分可以看到关联前的数据为何。
    H\?r0PU4y138711
    (fqi9BI&G#X1387113. 执行脚本验证关联是OK的。51Testing软件测试网!?1cxbR9j4y4S
    Correlation Studio51Testing软件测试网u6jPv-VZ2U
    当录制的应用系统不属于VuGen预设支持的应用系统时,Rule Correlation可能既无法发挥作用,这时可以利用Correlation Studio来做关联。
    -V7V ir4c;r ]138711Correlation Studio会尝试找出录制时与执行时,服务器响应内容的差异部分,藉以找出需要关联的数据,并建立关联。
    S'@i o0?138711使用Correlation Studio的步骤如下:
    $g RY9B`/E g$Ju1387111. 录制脚本并执行
    OJ+|&XBJT7}]1387112. 执行完毕后,VuGen会跳出下面的【Scan Action for Correlation】窗口,询问您是否要扫描脚本并建立关联,按下【Yes】按钮。
    N9o5pv1G3v];l138711
    N6s_T Y1387113. 扫描完后,可以在脚本下方的【Correlation Results】中看到扫描的结果。
    )~u0W}i:r4OO138711
    c2s,J+e$moBb1387114. 检查一下扫瞄的结果后,选择要做关联的数据,然后按下【Correlate】按钮,一笔一笔做,或是按下【Correlate All】让VuGen一次就对所有的数据建立关联。51Testing软件测试网.b HH,MF$|UC5~
    注意:由于Correlation Studio会找出所有有变动的数据,但是并不是所有的数据都需要做关联,所以不建议您直接用【Correlate All】。
    1_B^Zf+~1I T9T|1387115. 一般来说,您必须一直重复步骤1~4直到所有需要做关联的数据都找出来为止。因为有时前面的关联还没做好之前,将无法执行到后面需要做关联的部份。
    $r O_g8G+h)p138711有可能有些需要做关联的动态数据,连Correlation Studio都无法侦测出来,这时您就需要自行做手动关联了。
    ;b,{&` p,tnqS4UZ138711手动关联51Testing软件测试网B Md2C&G0N
    手动关联的执行过程大致如下:
    E0QR1l(e[[Q1387111. 使用相同的业务流程与数据,录制二份脚本51Testing软件测试网 \Bp$C'@kx
    2. 使用WinDiff工具协助找出需要关联的数据
    $mvc"n8XZq A1387113. 使用web_reg_save_param函数手动建立关联51Testing软件测试网.pu{R4_[ \
    4. 将脚本中有用到关联的数据,以参数取代
    'ib5T+^8|/X TI*O138711接下来将详细的说明如何执行每个步骤51Testing软件测试网B{.iC+B"G
    使用相同的业务流程与数据,录制二份脚本
    kJU \ c0{Qqm1387111. 先录制一份脚本并存档。51Testing软件测试网&g L#gHo[B x
    2. 依照相同的操作步骤与数据录制第二份脚本并存盘。注意,所有的步骤和输入的数据一定都要一样,这样才能找出由服务器端产生的动态数据。
    $o|0U-k2t#V{138711有时候会遇到真的无法使用相同的输入数据,那您也要记住您使用的输入数据,到时才能判断是您输入的数据,还是变动的数据。51Testing软件测试网Y TOR;qRp1C
    使用WinDiff工具协助找出需要关联的数据51Testing软件测试网ED1]/UIr
    1. 在第二份脚本中,点选VuGen的【Tools】>【Compare with Vuser…】,并选择第一份脚本。
    e0KB\P^4dq1387112. 接着WinDiff会开启,同时显示二份脚本,并显示有差异的地方。WinDiff会以一整行黄色标示有差异的脚本,并且以红色的字体显示真正差异的文字。(假如没看到红色字体,请点选【Options】>【View】>【Show Inline Differences】)。
    .Jznbl1387113. 逐一检视二份脚本中差异的部份,每一个差异都可能是需要做关联的地方。选取差异的脚本,然后复制。51Testing软件测试网8J1]k8vT(J
    在复制时,有时并不需要取整行脚本,可能只会选取脚本中的一部分。
    [C;R/V Q{+p138711注意:请忽略lr_thik_time的差异部份,因为lr_thik_time是用来模拟每个步骤之间使用者思考延迟的时间。
    ;s"\+D;|F6^ qXK M13871151Testing软件测试网#@my1GJ ` K
    4. 接着要在Recording Log(单一protocol)或是Generation Log(多重protocol)中找这个值。将鼠标光标点到Recording Log的第一行开头,按下Ctrl+F,开启【Find】窗口,贴上刚刚复制的脚本,找出在Recording Log第一次出现的位置。51Testing软件测试网`U1r$\!F2@ oz6R{'{ ^

    kI `,N$z t-M#v138711结果会有二种:51Testing软件测试网3aj}3a'x-{Z
    o 在Recording Log中找不到要找的数据,这时请先确认您找对了脚本,毕竟现在开启了二个几乎一样的脚本,很容易弄错。51Testing软件测试网)w ]2CiO
    o 在Recording Log中找到了要找的数据,这时要确认数据是从服务器端传送过来的。首先可以先检查数据的标头,从标头的Receiving response可以知道数据是从服务器端传送到client端的。假如此数据第一次出现是在Sending request中,则表示此数据是由client端产生,不需要做关联,但是有可能需要做参数化(parameterized)。51Testing软件测试网G)ZC(P3x$T"b{
    您要找的标头格式如下:
    j)?jPoI!f138711*** [tid=b9 Action1 2] Receiving response from host astra.merc-int.com:80 ( 25/11/2002 12:04:00 )
    T7ZBz5_ {*B+[,U138711
    ~ UR4VY:F{"e1387115. 现在您已经找到录制二次都不一样,而且是由服务器所产生的动态数据了,而此数据极有可能需要做关联。
    3E^U hp}?s138711使用web_reg_save_param函数手动建立关联
    !}N.eTJ5T(C(D138711在找到是由服务器所产生的动态数据之后,接下来要做的就是找出适当的位置,使用web_reg_save_param函数,将这个动态数据撷取到某个参数中。
    p+uL x{"q6ARK@1387111. 要在哪里使用web_reg_save_param函数?51Testing软件测试网d kNO~(S
    在之前的步骤,我们已经在Execution Log找到可能需要关联的动态数据。在Execution Log中选取动态数据前的文字然后复制,我们将会利用这段文字,来帮助我们找出要关联的动态数据。51Testing软件测试网El b1GRy-r.]
    51Testing软件测试网 Xt%H5Bruu2f#u
    不过在这之前我们要先找出使用web_reg_save_param函数的正确位置,所以我们要再重新执行一遍脚本,而且这次会开启所有的Log。
    M%|Z$Z~6WVO1387111. 在VuGen中点选【Vuser】>【Run-Time Settings】。
    OF W$J}1387112. 点选【General】>【Log】。
    |-hw6U%fw pc1387113. 勾选【Enable logging】、【Always sends messages】、【Extended log】,以及【Extended log】下的所有选项。51Testing软件测试网Iuz0bf*wn5ap@
    4. 按下【OK】就可以执行脚本了。
    K"N1I4C+H^%E138711执行完脚本之后,在Execution Log中搜寻刚刚复制的字符串。找到字符串后,在字符串前面会有A.tion1.c(7),这个7就是到时候要插入web_reg_save_param函数的位置,也就是要插入到脚本的第7行。
    dJ rc@;t-x}K[138711在脚本的第7行前插入一行空白行,然后输入
    6aaINtB r138711web_reg_save_param(“UserSession”,51Testing软件测试网m&}UW/p
    “UserSession” 这个 “UserSession” 就是到时要使用的参数名称,建议给个有意义的名字。
    QW f%f#m9W;sL*m@138711注意:到这里整个web_reg_save_param函数还没完成。51Testing软件测试网0U ss{o

    &|^kMD1bJR:BW1387112. 找出web_reg_save_param中要用到的边界
    1EZS/{)l c f138711web_reg_save_param函数主要是透过动态数据的前面和后面的固定字符串,来辨识要撷取的动态数据的,所以我们还需要找出动态数据的边界字符串。
    0^V.uCH/Y S7]f138711找出左边界字符串51Testing软件测试网 {6LW`P"C
    再回到Execution Log中,选取动态数据前的字符串并且复制它。51Testing软件测试网.Y} f7W(h Q/Gv
    这时会有个问题,到底要选取多少字符串才足以唯一识别要找的动态数据呢?建议是越多越好,但是尽量不要包含到特殊字符。
    8v\S1Lea2v B2MI8m138711在这边我们选取「input type=hidden name=userSession value=」字符串。选好之后,还要再确认一次这段字符串真的是可以唯一识别的,所以我们在Execution Log中透过Ctrl+F的搜寻,找找看这段字符串是否可以找到要找的动态数据。假如找不到,web_reg_save_param函数还有个ORD参数可以使用,ORD参数可以设定出现在第几次的字符串才是要找的字符串。51Testing软件测试网!|8f!q&dB/b(Y
    将这个边界字符串加到未完成的web_reg_save_param函数中:51Testing软件测试网2t_ y U*q Y
    web_reg_save_param(“UserSession”, “LB= input type=hidden name=userSession value=”,
    {_t;tA;z6i138711找出右边界字符串51Testing软件测试网&P5\%r2py/H Zm`&T
    接下来要找出动态数据的右边界字符串,这个字符串就比较好找了,从动态数据的最后一个字符开始,通常就是我们要找的右边界字符串了。
    ](i9_(h\ks+?138711以这个例子来看,就是「>」,所以再把右边界字符串加入,web_reg_save_param函数中,这时web_reg_save_param函数已经快完成了。最后再加上「LAST);」就完成整个web_reg_save_param函数了。
    | ra8N G138711web_reg_save_param(“UserSession”, “LB= input type=hidden name=userSession value=”, “RB=>”, LAST);51Testing软件测试网(J,D's,M:w4T
    51Testing软件测试网q2?b'DP%{]HN
    将脚本中有用到关联的数据,以参数取代51Testing软件测试网$V)PkPM:B b(z ]y3o
    当使用web_reg_save_param建立参数后,接下来就是用“UserSession”参数去取代脚本中写死的(hard-coded)资料。
    :C2N:vX0a$iPWL o z1`138711范例:51Testing软件测试网sTXdO!`2]s
    51Testing软件测试网7A&S pp#L
    “Name=userSession”, “Value=75893.0884568651DQADHfApHDHfcDtccpfAttcf”, ENDITEM,51Testing软件测试网)x~}j F)?
    换成51Testing软件测试网0kAcuA5a2d
    “Name=userSession”, “Value={UserSession}”, ENDITEM,51Testing软件测试网} C2]s|;AP$V%y
    51Testing软件测试网n^)?CW:C
    到这里您已经完成了一个关联了,接下来就是执行脚本,是否能成功运行,假如还是有问题,就要检查看看是否还需要再做另一个关联。51Testing软件测试网+_ lm@$STJ+B
    关于 web_reg_save_param 函数
    0Y"Y#uA+R-W+Q1[138711对于关联(correlation)来说,web_reg_save_param是最重要的一个函数,其功能是在下载的网页内容中,透过设定的边界字符串,找出特定的数据并将其储存在一个参数中,以供后续脚本使用。51Testing软件测试网.k-XR%d8i pF|
    接下来将针对web_reg_save_param做比较详细的说明。
    K4},q(C3I#L%nE|138711Service and registration type function
    ~+].Gm%M~ D138711web_reg_save_param是一个Service function。service function主要是用来完成一些特殊的工作的,如关联、设定proxy、提供认证信息等,当其作用时,不会对网页的内容做任何的修改。
    q5K"PJ B%R:pHXb138711web_reg_save_param同时也是一个registration type function (只要函数名称中包含_reg_的字眼,表示其为registration type function)。registration type function意味着其真正作用的时机是在下一个action function完成时执行的。举例来说,当某个web_url执行时所接收到的网页内容中包含了要做关联的动态数据,则必须将web_reg_save_param放在此web_url之前,则web_reg_save_param会在web_url执行完毕后,也就是网页内容都下载完后,再执行web_reg_save_param找寻要做关联的动态数据并建立参数。
    Gh*dn2FkHQ138711所以要记住一点,要使用registration type function时,要注意其放置的位置必须在要作用的action function之前。51Testing软件测试网e8z,fcq.v
    语法
    9^!yq#| ~w b138711int web_reg_save_param(const char *ParamName, <list of Attributes>, LAST);
    l;I+Vc&_@138711参数说明
    lb V1X OF138711ParamName:存放动态数据的参数名称
    l4M$|6w)z9v#_138711list of Attributes:其它属性,包含 Notfound, LB, RB, RelFrameID, Search, ORD, SaveOffset, Convert, 以及 SaveLen。属性值不分大小写,例如 Search=all。以下将详细说明每个属性值的意义:51Testing软件测试网 r I8w;K2d ]E
    • Notfound:指定当找不到要找的动态数据时该怎么处置。
    +pkpo f sA6`f138711o Notfound=error:当找不到动态数据时,发出一个错误讯息。假如没设定此属性,此为LoadRunner的默认值。51Testing软件测试网@#L"~p?`fovs
    o Notfound=warning:当找不到动态数据时,不发出错误讯息,只发出警告,脚本也会继续执行下去不会中断。在对角本除错时,可以使用此属性值。
    z!tE$_B!\T&lT138711• LB:动态数据的左边界字符串。此属性质是必须要有的,而且区分大小写。
    _9J1LpI|sx138711• RB:动态数据的右边界字符串。此属性质是必须要有的,而且区分大小写。51Testing软件测试网X%yRw n B
    • RelFrameID:相对于URL而言,欲搜寻的网页的Frame。此属性质可以是All或是数字,而且可有可无。51Testing软件测试网)I#q BZ?-C
    • Search:搜寻的范围。可以是Headers(只搜寻headers)、Body(只搜寻body部分,不搜寻header)、Noresource(只搜寻body部分,不搜寻header与resource)或是All(搜寻全部范围,此为默认值)。此属性质可有可无。51Testing软件测试网2f3|(i#\/I0b X Q
    • ORD:指明从第几次出现的左边界开始才是要撷取的数据。此属性质可有可无,默认值是1。假如值为All,则所有找到符合的数据会储存在数组中。
    ?q}"p*h5Fc138711• SaveOffset:当找到符合的动态数据时,从第几个字符开始才开始储存到参数中。此属性质不可为负数,其默认值为0。51Testing软件测试网 ea%TK#a`u,M^
    • Convert:可能的值有二种:51Testing软件测试网 m7D7VWB2x"v:vZ
    o HTML_TO_URL: 将HTML-encoded数据转成URL-encoded数据格式
    H(Z#N#LW4]l138711o HTML_TO_TEXT:将HTML-encoded数据转成纯文字数据格式
    Fd]}7bNu] iE138711• SaveLen:从offect开始算起,到指定的长度内的字符串,才储存到参数中。此参数可有可无,默认值是-1,表示储存到结尾整个字符串。51Testing软件测试网 @2o`j0] x
    范例
    )by6L*r:s'T\Oz138711web_reg_save_param("A", "LB/ic=<a href=", "RB='>", "Ord=All", LAST);nner会搜寻网页中所有以 「<a href=」 开头,且以 「’>」结束,当中包含的字符串,并且储存在「A」参数中。
    &v|?M [ w9_#Rv []/l [{138711Tips and Tricks51Testing软件测试网6GK]#Nh&~0T
    以下提供一些关联的常见问题:51Testing软件测试网6U8C&ZhBd
    • 如何打印出参数值?51Testing软件测试网yc4_8hRqA)X
    lr_output_message这二个函数来做到。例如:51Testing软件测试网7i;_0b7x"T9I*S
    lr_output_message(“Value Captured = %s”, lr_eval_string(“{ParameterName}”));
    v*a[*I_6E6I ~'VzT138711lr_eval_string与lr_output_message函数的使用说明请参考LoadRunner Online Function Reference。51Testing软件测试网*u vD%w'Ys6D!U
    • 在脚本的data目录下找不到路制时的快照(snapshot)51Testing软件测试网vk#H*mvs4{y0E1K
    造成在脚本的data目录下找不到路制时的快照(snapshot)的可能原因如下:51Testing软件测试网r9Nu:N^+Ty
    o 脚本是由VuGen 6.02或更早的版本所录制的51Testing软件测试网 JY&W/Js4a
    o 汇入的Action不会包含快照(snapshot)的档案
    $snGG}1X138711o 脚本是储存在只读的目录下,早成VuGen无法储存执行时撷取的快照(snapshot)51Testing软件测试网A%[]zm ~
    o 某些步骤并不会产生快照(snapshot),如浏览某个资源
    I0j {)Gb(aA138711o 快照(snapshot)功能被取消51Testing软件测试网arW8D"@
    【Tools】>【General options】>【Correlation】tab >【Save correlation information during replay】51Testing软件测试网l1m OBj i
    • 开启WinDiff时出现「File no longer available」的错误讯息
    6v k?s,^4a138711WinDiff这个工具有些限制,无法开启包含空格符的目录或是脚本,所以建议命名时不要使用空格符,并且尽可能将名称取短一点。
    ,W&I$jA3bkH c/C~138711• 录制时突然跳出【Correlation warning】对话窗口51Testing软件测试网m QW2FM1O V H
    当你有勾选自动关联的【Issue a popup message and let me decide online】选项,当VuGen发现有可能要做关联的数据时,就会跳出【Correlation warning】的窗口,询问你要做关联(Correlation in scrīpt)还是要忽略(Ignore)。51Testing软件测试网;yb9p td&|X
    另外你也可以勾选【Perform. correlation in scrīpt】,让VuGen自动作关联,不会再跳出询问窗口。
    X ILP/\"D#[138711或是勾选【Disable correlation engine】,关闭自动关联的功能。51Testing软件测试网R0k-s2~ t0m E

    a+N&aW:s138711• 如何手动启动「Scan action for correlation」的功能51Testing软件测试网G%IF!J`\
    要手动启动「Scan action for correlation」的功能,请先执行脚本一次后,点选【Vuser】>【Scan Action for Correlation】。
    ,Z$]\Cx138711
    `[%[D$R3_ L1~g138711• 执行完脚本后并未出现【Scan Action for Correlation】窗口51Testing软件测试网F:nS``}P Y0i#]
    要启用【Scan Action for Correlation】功能,请点选【Tools】>【General options】>【Correlation】tab,勾选【Show Scan for correlation popup after replay of Vuser】选项。

  • (转)LoadRunner监视的性能计数器

    2009-03-21 15:14:11

    今天,我先把我整理的一些计数器及其阈值要求等贴出来,这些计数器是针对我对windows操作系统,C/S结构的sql server数据库及WEB平台.net产品测试时的一些计数器;大家可以继续补充,作过unix平台上oracle数据库测试及J2EE架构及WEBLOGIC方面测试的朋友,也希望把自己使用的计数器贴出来,让大家分享。
    好了,先说这些了,希望通过这个专题,最终能让大家对自己的测试结果进行分析。

    Memory:内存使用情况可能是系统性能中最重要的因素。如果系统“页交换”频繁,说明内存不足。“页交换”是使用称为“页面”的单位,将固定大小的代码和数据块从 RAM 移动到磁盘的过程,其目的是为了释放内存空间。尽管某些页交换使 Windows 2000 能够使用比实际更多的内存,也是可以接受的,但频繁的页交换将降低系统性能。减少页交换将显著提高系统响应速度。要监视内存不足的状况,请从以下的对象计数器开始:
    Available Mbytes:可用物理内存数. 如果Available Mbytes的值很小(4 MB 或更小),则说明计算机上总的内存可能不足,或某程序没有释放内存。


    page/sec:表明由于硬件页面错误而从磁盘取出的页面数,或由于页面错误而写入磁盘以释放工作集空间的页面数。一般如果pages/sec持续高于几百,那么您应该进一步研究页交换活动。有可能需要增加内存,以减少换页的需求(你可以把这个数字乘以4k就得到由此引起的硬盘数据流量)。Pages/sec 的值很大不一定表明内存有问题,而可能是运行使用内存映射文件的程序所致。


    page read/sec:页的硬故障,page/sec的子集,为了解析对内存的引用,必须读取页文件的次数。阈值为>5. 越低越好。大数值表示磁盘读而不是缓存读。
    由于过多的页交换要使用大量的硬盘空间,因此有可能将导致将页交换内存不足与导致页交换的磁盘瓶径混淆。因此,在研究内存不足不太明显的页交换的原因时,您必须跟踪如下的磁盘使用情况计数器和内存计数器:
    Physical Disk\ % Disk Time
    Physical Disk\ Avg.Disk Queue Length
    例如,包括 Page Reads/sec 和 % Disk Time 及 Avg.Disk Queue Length。如果页面读取操作速率很低,同时 % Disk Time 和 Avg.Disk Queue Length的值很高,则可能有磁盘瓶径。但是,如果队列长度增加的同时页面读取速率并未降低,则内存不足。
    要确定过多的页交换对磁盘活动的影响,请将 Physical Disk\ Avg.Disk sec/Transfer 和 Memory\ Pages/sec 计数器的值增大数倍。如果这些计数器的计数结果超过了 0.1,那么页交换将花费百分之十以上的磁盘访问时间。如果长时间发生这种情况,那么您可能需要更多的内存。


    Page Faults/sec:每秒软性页面失效的数目(包括有些可以直接在内存中满足而有些需要从硬盘读取)较page/sec只表明数据不能在内存的指定工作集中立即使用。
    Cache Bytes:文件系统缓存(File System Cache),默认情况下为50%的可用物理内存。如IIS5.0 运行内存不够时,它会自动整理缓存。需要关注该计数器的趋势变化
    如果您怀疑有内存泄露,请监视 Memory\ Available Bytes 和 Memory\ Committed Bytes,以观察内存行为,并监视您认为可能在泄露内存的进程的 Process\Private Bytes、Process\Working Set 和Process\Handle Count。如果您怀疑是内核模式进程导致了泄露,则还应该监视 Memory\Pool Nonpaged Bytes、Memory\ Pool Nonpaged Allocs 和 Process(process_name)\ Pool Nonpaged Bytes。


    Pages per second :每秒钟检索的页数。该数字应少于每秒一页。

    Process:
    %Processor Time: 被处理器消耗的处理器时间数量。如果服务器专用于sql server,可接受的最大上限是80-85%
    Page Faults/sec:将进程产生的页故障与系统产生的相比较,以判断这个进程对系统页故障产生的影响。
    Work set: 处理线程最近使用的内存页,反映了每一个进程使用的内存页的数量。如果服务器有足够的空闲内存,页就会被留在工作集中,当自由内存少于一个特定的阈值时,页就会被清除出工作集。
    Inetinfo:Private Bytes:此进程所分配的无法与其它进程共享的当前字节数量。如果系统性能随着时间而降低,则此计数器可以是内存泄漏的最佳指示器。

    Processor:监视“处理器”和“系统”对象计数器可以提供关于处理器使用的有价值的信息,帮助您决定是否存在瓶颈。
    %Processor Time:如果该值持续超过95%,表明瓶颈是CPU。可以考虑增加一个处理器或换一个更快的处理器。
    %User Time:表示耗费CPU的数据库操作,如排序,执行aggregate functions等。如果该值很高,可考虑增加索引,尽量使用简单的表联接,水平分割大表格等方法来降低该值。
    %Privileged Time:(CPU内核时间)是在特权模式下处理线程执行代码所花时间的百分比。如果该参数值和"Physical Disk"参数值一直很高,表明I/O有问题。可考虑更换更快的硬盘系统。另外设置Tempdb in RAM,减低"max async IO","max lazy writer IO"等措施都会降低该值。
    此外,跟踪计算机的服务器工作队列当前长度的 Server Work Queues\ Queue Length 计数器会显示出处理器瓶颈。队列长度持续大于 4 则表示可能出现处理器拥塞。此计数器是特定时间的值,而不是一段时间的平均值。
    % DPC Time:越低越好。在多处理器系统中,如果这个值大于50%并且Processor:% Processor Time非常高,加入一个网卡可能会提高性能,提供的网络已经不饱和。

    Thread
    ContextSwitches/sec: (实例化inetinfo 和dllhost 进程) 如果你决定要增加线程字节池的大小,你应该监视这三个计数器(包括上面的一个)。增加线程数可能会增加上下文切换次数,这样性能不会上升反而会下降。如果十个实例的上下文切换值非常高,就应该减小线程字节池的大小。

    Physical Disk:
    %Disk Time %:指所选磁盘驱动器忙于为读或写入请求提供服务所用的时间的百分比。如果三个计数器都比较大,那么硬盘不是瓶颈。如果只有%Disk Time比较大,另外两个都比较适中,硬盘可能会是瓶颈。在记录该计数器之前,请在Windows 2000 的命令行窗口中运行diskperf -yD。若数值持续超过80%,则可能是内存泄漏。
    Avg.Disk Queue Length:指读取和写入请求(为所选磁盘在实例间隔中列队的)的平均数。该值应不超过磁盘数的1.5~2 倍。要提高性能,可增加磁盘。注意:一个Raid Disk实际有多个磁盘。
    Average Disk Read/Write Queue Length:指读取(写入)请求(列队)的平均数。
    Disk Reads(Writes)/s: 物理磁盘上每秒钟磁盘读、写的次数。两者相加,应小于磁盘设备最大容量。
    Average Disksec/Read: 指以秒计算的在此盘上读取数据的所需平均时间。
    Average Disk sec/Transfer:指以秒计算的在此盘上写入数据的所需平均时间。
    Network Interface:
    Bytes Total/sec :为发送和接收字节的速率,包括帧字符在内。判断网络连接速度是否是瓶颈,可以用该计数器的值和目前网络的带宽比较

    SQLServer性能计数器:
    Access Methods(访问方法) 用于监视访问数据库中的逻辑页的方法。
    . Full Scans/sec(全表扫描/秒) 每秒不受限的完全扫描数。可以是基本表扫描或全索引扫描。如果这个计数器显示的值比1或2高,应该分析你的查询以确定是否确实需要全表扫描,以及S Q L查询是否可以被优化。
    . Page splits/sec(页分割/秒)由于数据更新操作引起的每秒页分割的数量。
    Buffer Manager(缓冲器管理器):监视 Microsoft&reg; SQL Server? 如何使用: 内存存储数据页、内部数据结构和过程高速缓存;计数器在 SQL Server 从磁盘读取数据库页和将数据库页写入磁盘时监视物理 I/O。 监视 SQL Server 所使用的内存和计数器有助于确定: 是否由于缺少可用物理内存存储高速缓存中经常访问的数据而导致瓶颈存在。如果是这样,SQL Server 必须从磁盘检索数据。 是否可通过添加更多内存或使更多内存可用于数据高速缓存或 SQL Server 内部结构来提高查询性能。
    SQL Server 需要从磁盘读取数据的频率。与其它操作相比,例如内存访问,物理 I/O 会耗费大量时间。尽可能减少物理 I/O 可以提高查询性能。
    .Page Reads/sec:每秒发出的物理数据库页读取数。这一统计信息显示的是在所有数据库间的物理页读取总数。由于物理 I/O 的开销大,可以通过使用更大的数据高速缓存、智能索引、更高效的查询或者改变数据库设计等方法,使开销减到最小。
    .Page Writes/sec (.写的页/秒) 每秒执行的物理数据库写的页数。
    .Buffer Cache Hit Ratio. 在“缓冲池”(Buffer Cache/Buffer Pool)中没有被读过的页占整个缓冲池中所有页的比率。可在高速缓存中找到而不需要从磁盘中读取的页的百分比。这一比率是高速缓存命中总数除以自 SQL Server 实例启动后对高速缓存的查找总数。经过很长时间后,这一比率的变化很小。由于从高速缓存中读数据比从磁盘中读数据的开销要小得多,一般希望这一数值高一些。通常,可以通过增加 SQL Server 可用的内存数量来提高高速缓存命中率。计数器值依应用程序而定,但比率最好为90% 或更高。增加内存直到这一数值持续高于90%,表示90% 以上的数据请求可以从数据缓冲区中获得所需数据。
    . Lazy Writes/sec(惰性写/秒)惰性写进程每秒写的缓冲区的数量。值最好为0。
    Cache Manager(高速缓存管理器) 对象提供计数器,用于监视 Microsoft&reg; SQL Server? 如何使用内存存储对象,如存储过程、特殊和准备好的 Transact-SQL 语句以及触发器。
    . Cache Hit Ratio(高速缓存命中率,所有Cache”的命中率。在SQL Server中,Cache可以包括Log Cache,Buffer Cache以及Procedure Cache,是一个总体的比率。) 高速缓存命中次数和查找次数的比率。对于查看SQL Server高速缓存对于你的系统如何有效,这是一个非常好的计数器。如果这个值很低,持续低于80%,就需要增加更多的内存。
    Latches(闩) 用于监视称为闩锁的内部 SQL Server 资源锁。监视闩锁以明确用户活动和资源使用情况,有助于查明性能瓶颈。
    . Average Latch Wait Ti m e ( m s ) (平均闩等待时间(毫秒)) 一个SQL Server线程必须等待一个闩的平均时间,以毫秒为单位。如果这个值很高,你可能正经历严重的竞争问题。
    . Latch Waits/sec (闩等待/秒) 在闩上每秒的等待数量。如果这个值很高,表明你正经历对资源的大量竞争。
    Locks(锁) 提供有关个别资源类型上的 SQL Server 锁的信息。锁加在 SQL Server 资源上(如在一个事务中进行的行读取或修改),以防止多个事务并发使用资源。例如,如果一个排它 (X) 锁被一个事务加在某一表的某一行上,在这个锁被释放前,其它事务都不可以修改这一行。尽可能少使用锁可提高并发性,从而改善性能。可以同时监视 Locks 对象的多个实例,每个实例代表一个资源类型上的一个锁。
    . Number of Deadlocks/sec(死锁的数量/秒) 导致死锁的锁请求的数量
    . Average Wait Time(ms) (平均等待时间(毫秒)) 线程等待某种类型的锁的平均等待时间
    . Lock Requests/sec(锁请求/秒) 每秒钟某种类型的锁请求的数量。
    Memory manager:用于监视总体的服务器内存使用情况,以估计用户活动和资源使用,有助于查明性能瓶颈。监视 SQL Server 实例所使用的内存有助于确定:
    是否由于缺少可用物理内存存储高速缓存中经常访问的数据而导致瓶颈存在。如果是这样,SQL Server 必须从磁盘检索数据。
    是否可以通过添加更多内存或使更多内存可用于数据高速缓存或 SQL Server 内部结构来提高查询性能。
    Lock blocks:服务器上锁定块的数量,锁是在页、行或者表这样的资源上。不希望看到一个增长的值。
    Total server memory:sql server服务器当前正在使用的动态内存总量.

    监视IIS需要的一些计数器
    Internet Information Services Global:
    File Cache Hits %、File CacheFlushes、File Cache Hits
    File Cache Hits %是全部缓存请求中缓存命中次数所占的比例,反映了IIS 的文件缓存设置的工作情况。对于一个大部分是静态网页组成的网站,该值应该保持在80%左右。而File Cache Hits是文件缓存命中的具体值,File CacheFlushes 是自服务器启动之后文件缓存刷新次数,如果刷新太慢,会浪费内存;如果刷新太快,缓存中的对象会太频繁的丢弃生成,起不到缓存的作用。通过比较File Cache Hits 和File Cache Flushes 可得出缓存命中率对缓存清空率的比率。通过观察它两个的值,可以得到一个适当的刷新值(参考IIS 的设置ObjectTTL 、MemCacheSize 、MaxCacheFileSize)
    Web Service:
    Bytes Total/sec:显示Web服务器发送和接受的总字节数。低数值表明该IIS正在以较低的速度进行数据传输。
    Connection Refused:数值越低越好。高数值表明网络适配器或处理器存在瓶颈。
    Not Found Errors:显示由于被请求文件无法找到而无法由服务器满足的请求数(HTTP状态代码404)

  • (转)LoadRunner测试过程中调用dll文件的制作与使用

    2009-01-17 16:35:36

    在Windows操作系统中使用DLL有很多优点,最主要的一点是多个应用程序、甚至是不同语言编写的应用程序可以共享一个DLL文件,真正实现了资源"共享",大大缩小了应用程序的执行代码,更加有效的利用了内存;使用DLL的另一个优点是DLL文件作为一个单独的程序模块,封装性、独立性好,在软件需要升级的时候,开发人员只需要修改相应的DLL文件就可以了,而且,当DLL中的函数改变后,只要不是参数的改变,程序代码并不需要重新编译。这在编程时十分有用,大大提高了软件开发和维护的效率。

           在LR下也可以直接调用动态链接库文件,针对一些使用LR脚本编写比较烦琐的方法可以考虑此方法(比如各种加解密算法的实现,数据库的操作等),并能够使测试脚本简单明了。鉴于此,本人初次尝试了如何制作DLL文件并在LR中使用。

           1、dll文件的制作

           在Visual C++6.0开发环境下,打开File-New-Project选项,可以选择Win32 Dynamic-Link Library来创建一个名为dllfortest的空的dll工程(这只是方法之一)。

           在该项目中新建一个dllfortest.h和dllfortest.cpp文件,文件的内容如下:

    //dllfortest.h

    extern "C" _declspec(dllexport) int Max(int a, int b, int c);

    extern "C" _declspec(dllexport) int Min(int a, int b, int c);

     

    //dllfortest.cpp  包含一个计算三个整数中最大值和最小值的方法

    #include"dllfortest.h"

    int Max(int a, int b, int c)

    {

           int Res;

           Res = (a>b? a:b)>c? (a>b? a:b):c;

           return Res;

    }

    int Min(int a, int b, int c)

    {

           int Res;

           Res = (a>b? b:a)>c? c:(a>b? b:a);

           return Res;

    }

    该动态链接库编译成功后,打开dllfortest工程目录下的debug目录下,可以看到生成了一个dllfortest.dll文件,这就是我们想要的文件。

           2、dll文件在LR中的调用

           打开LR VU Generator,选择C Vuser协议(或其他支持C的协议),进入编辑界面。Action部分如下所示:

    Action()

    {

           lr_load_dll("dllfortest.dll");

           lr_message("Max Result is %d",Max(100,200,67));

           lr_message("Min Result is %d",Min(55,97,63));

           return 0;

    }

    将dllfortest.dll文件复制到脚本所在的目录(如果不复制的话,lr_load_dll的参数应该写成dll文件的绝对路径),如果编译没有报错的话,就可以直接运行了。

    运行结果如下:

    Virtual User scrīpt started

    Starting action vuser_init.

    Ending action vuser_init.

    Running Vuser...

    Starting iteration 1.

    Starting action Action.

    Max Result is 200

    Min Result is 55

    Ending action Action.

    Ending iteration 1.

    Ending Vuser...

    Starting action vuser_end.

    Ending action vuser_end.

    Vuser Terminated.

     

    如果在脚本中用到了DLL文件中并不存在的方法名时,编译也能通过,但是运行时LR会报错,提示不存在该方法

    比如我们在脚本中添加一句:

           lr_message("Min Result is %d",Sum(55,97,63));  //Sum方法并不存在

    运行时错误信息如下:

    Action.c(7): Error: C interpreter run time error: Action.c (7):  Error -- Unresolved symbol : Sum.

    Action.c(7): Notify: CCI trace: Compiled_code(0): Action()

    .

    这个例子并没有体现出DLL文件调用的优点,因为调用的方法在LR中用C直接就可以完成,但涉及到LR中完不成的任务时,或许dll文件的作用就体现出来了

    example:
    LoadRunner提供了功能强大的API集合,足够应付大多数性能测试的需求。但在某些情况下,这些API仍然有覆盖不到的地方。例如,我们有一个WEB应用,该应用有一个页面输入用户的信息,为了安全起见,用户输入的信息在提交之前都要先进行加密处理,加密处理通过本地的COM组件实现。

    对这个要求而言,LoadRunner的现有API不能提供直接支持,因为LoadRunner在录制脚本时只录制数据交互,因此,COM的加密处理过程是不能录制下来的。在LoadRunner的脚本中,可能只有类似以下的语句描述了这个过程:

    …………
    web_url("userinfo",
        "URL=http://testweb/userinfo.aspx",
        "TargetFrame=",
        "Resource=0",
         "Referer=",
         LAST);

    web_submit_form("login ",
    "Snapshot=t4.inf",
    ITEMDATA,
    "Name=username", "Value=4e92Sh6d394g", ENDITEM,
    "Name=password", "Value=932A2hf34U18", ENDITEM,
    LAST);
    …………

    从脚本可以看到,输入的数据是加密后的数据,但LR没有录制到加密过程。

    假设加密函数所在的DLL名为security.dll,用于加密的函数名为encode,则一种可能的对脚本的修改方法如下代码所示。
    …………
    char *encode_username, *encode_password, *orgin_username, *orgin_password;
    char* uservalue, passvalue;
    int ret;
    ……
    web_url("userinfo",
         "URL=http://testweb/userinfo.aspx",
         "TargetFrame=",
         "Resource=0",
          "Referer=",
          LAST);

    orgin_username = lr_eval_string(“{ username }”); //获取参数的值
    orgin_password = lr_eval_string(“{ password }”);

    ret = lr_load_dll(“security.dll”);   //加载DLL库

    encode(origin_username, encode_username);  //调用encode函数
    encode(origin_password, encode_password);


    sprintf(uservalue, “Value=%s”, encode_username);
    sprintf(passvalue, “value=%s”, encode_password);

    web_submit_form("login ",
      "Snapshot=t4.inf",
      ITEMDATA,
      "Name=username", uservalue, ENDITEM,
      "Name=password", passvalue, ENDITEM,
      LAST);


    注意:有些脚本录制需要相应的patch的支持,如录制DotNet编写的应用程序你需要把lr78安装盘\ Patches\Trap_for_.net_patch文件夹中trpfnc32.32dll拷贝到loadrunner\bin路径下,才能正常工作。

  • (转)调用外部Dll

    2009-01-17 15:44:53

    调用外部Dll的点点滴滴  

    调用外部DLL的方法有两种:

    1.     (单个脚本中)在脚本中是使用 lr_load_dll 函数。

    2.     (全局设置,所有脚本)通过修改 mdrv.dat 文件实现。

    对DLL的要求       VuGen只能识别标准C编译的DLL, 所以使用VC6创建的函数必须在函数开头加上extern "C",它告诉编译器对这个函数按照标准C的方式进行编译。而如果你想调用C#编译出来DLL,那就只能望而却步啦。如何想查看DLL中是否有符合要求的导出函数,可以使用微软的SDK里自带的Dependency Walker工具。    
          
    DLL的创建    启动VC6,新建一个Win32 Dynamic-Link Library的工程,取名:LRDllTest
        在这里,我们创建一个简单的求和函数Sum,并什么为导出函数,关键代码如下:
       
        #define LRDLLTEST_API __declspec(dllexport)
        extern
    "C" LRDLLTEST_API int Sum(int a , int b);
        //a + b
        LRDLLTEST_API int Sum(int a , int b)
        {
            return a + b;
        }
        编译,生成DLL:LRDllTest.dll

    lr_load_dll方法    有了符合要求的DLL,调用lr_load_dll函数显得非常的简单。lr_load_dll的函数原型是:
        lr_load_dll(library_name);    所以,只需要调用该函数,传入需要引用的DLL路径,如果DLL放在脚本目录里,可直接写相对路径。这里,我推荐把该函数放在vuser_init这个Action里,一方面是由于vuser_init只会执行一次,如果我们放在中间的那个默认的Action中的话,DLL可能会被装载多次,这是没有必要的。另一方面,装载DLL也需要一定的性能开销,所以作为初始环境设置将它放在vuser_init中更加合理。
        调用lr_load_dll装载DLL后,就可以任意使用该DLL中的导出函数,而不需要再去做任何声明了。嗯,用起来的确很简单,VuGen中代码如下:
       
        vuser_init()
        {
            lr_load_dll("LRDllTest.dll");
            return
    0;
        }
        Action()
        {
            int a = Sum(1,2);
            lr_output_message("a = %d",a);
            return
    0;
        }
    Load Generators调用远程机器进行加压时调用lr_load_dll的方法    有人会遇到这种情况,使用lr_load_dll加载DLL的脚本在本机是可以顺利执行的,但是在Controller中通过负载生成器(Load Generators)调用远程机器执行脚本时,脚本会无法顺利执行,错误信息:
        Error: CCI security error:You are running under secure mode and the function ci_load_dll is not allowed in this mode.
        错误信息让人百思不得其解,不过能够猜到,肯定是远程机器无法调用加载的DLL所致。
        众里寻他千百度,暮然回首,解决办法其实是如此的简单:
        菜单“File-Add file to scrīpt”,把要引用的DLL加进来,一切搞定!注意,Agent的Enable Firewall Agent选项不要勾上。 mdrv.dat方法    这个办法比较毒,通过修改mdrv.dat文件,无需调用lr_load_dll即可使用该DLL任何导出函数。具体实施方法如下:

    1.     将LRDllTest.dll拷贝到LoadRunner安装路径的Bin目录下。

    2.     修改mdrv.dat文件(安装路径的dat目录下),因为选择的是默认的Web协议,所以找到[lrun_api]节点,在后面加上一句:

    WINNT_DLLS=LRDllTest.dll

        OK,再试试不使用lr_load_dll函数,直接调用LRDllTest.dll中的Sum函数吧!
        了解详细的内容请参考LR的帮助:HP LoadRunner Virtual User Generator User's Guide > Appendixes >Calling External Functions > Loading a DLL—Globally

    ****************************************************************************************

    lr_load_dll

    Loads an external DLL.

    Example:

    In the following example, lr_load_dll is used so that a standard Windows message box can be displayed during scrīpt replay:

    lr_load_dll("user32.dll");

    MessageBoxA(NULL, "This is the message body", "message_caption", 0);

  • (转)数字文件存储

    2009-01-06 13:20:26

    数据文件能保存脚本执行期间Vuser访问的数据,这些数据可以被存储在本地或全局文件中。如果拥有大量已知参数值,数据文件是非常有用的。

    数据文件中的数据以表格的形式存储。一个文件可以包含大量参数值,每一列都保存一个参数的数据。列的分隔由分隔符标记,例如逗号、"-"或者Tab符号等。如果使用文件作为参数的数据源,必须指定文件的名称和位置、包含数据的列、文件格式,包括列的分隔符、更新方法等内容。

    在下例中,就是使用文件作为参数的数据源,其数据文件包含了每个数据的ID编号及其相对应的名称,如图3-25所示。

    498)this.style.width=498;" border=0> 图3-25  数据文件存储设置

    在"File path"框中输入数据文件的名称,或者单击"Browse"(浏览)按钮指定现有数据文件的文件位置。默认情况下,所有新数据文件均被命名为"parameter_name.dat"并且存储在脚本的目录中。

    单击"Edit with Notepad"按钮,将打开记事本,在记事本文档中编辑此数据,其中第一行是参数名,第二行是参数的初始值。用表格的形式将其他列名和值输入到该文件中。使用分隔符(例如逗号或者制表符)来指示列分隔。对表格中的每个新行都要另起一行开始。

    "Select next row"下拉列表框有以下几个选项:

    1.Sequential:按照顺序一行行地读取。每一个Vuser都会按照相同的顺序读取文件中的参数值,选择"Sequential"方法系统会按照顺序向Vuser分配参数值。当正在运行的Vuser访问数据表格时,Vuser会提取下一个可用的数据行。

    如果在"Update Value on"(更新值的时间)列表框中指定了"Each iteration"(每次迭代),则Vuser将为每一次迭代从数据表格中提取下一个值。

    如果在"Update value on"列表框中指定了"Each occurrence"(每次出现),则Vuser将为每一次参数的出现从数据表格中提取下一个值,即使它在同一次迭代中。

    如果在"Update Value on"列表框中指定了"Once(一次)",则第一次迭代中分配的值就会在每个Vuser接下来所有的迭代中使用。

    例如表3-2列出了数据文件的参数值。

    表3-2  数据表格

    Kim

    David

    Michael

    Jane

    Ron

    Alice

    Ken

    Julie

    如果选择了"Each iteration",则所有Vuser就会在第一次迭代中使用Kim,第二次迭代中使用David,第三次迭代中使用Michael,依此类推。

    如果选择了"Each occurrence",则所有Vuser就会在第一次出现时使用Kim,第二次出现时使用David,第三次出现时使用Michael,依此类推。

    如果选择了"Once",则第一个Vuser为所有的迭代提取Kim,第二个Vuser为所有的迭代提取David,依此类推。

    如果在数据表格中没有足够的值,则VuGen返回到表格中的第一个值,循环继续直到测试结束。

    2.Random:在每次循环里随机地读取一个数据,但是在循环中一直保持不变。当测试开始运行时,"随机"方法为每个Vuser分配一个数据表格中的随机值。

    如果在"Update Value on"列表框中指定了"Each iteration",则Vuser将会为每一次迭代从数据表格中提取一个新的随机值。

    如果在"Update Value on"列表框中指定了"Each occurrence",则Vuser将会为每一次参数的出现从数据表格中提取一个新的随机值,即使它在同一次迭代中。

    如果在"Update Value on"列表框中指定了"Once",则第一次迭代中分配的随机值就会在该Vuser的所有迭代中使用。

    当从LoadRunner控制台运行一个方案时,您可以指定随机顺序的种子数。每个种子值代表用于测试执行的一个随机值顺序。每当使用该种子值时,都会将相同顺序的值分配给方案中的Vuser。如果在测试执行中发现问题,并且要使用相同的随机值顺序重复该测试,请启用"Random"选项。

    3.Unique:该方法为每一个Vuser的参数分配一个唯一的顺序值。

    如果在"Update Value on"列表框中指定了"Each iteration",则Vuser将为每一次迭代从数据表格中提取下一个唯一值。

    如果在"Update Value on"列表框中指定了"Each occurrence",则Vuser将会为每一次参数的出现从数据表格中提取一个新的唯一值,即使它在同一次迭代中。

    如果在"Update Value on"列表框中指定了"Once",则第一次迭代中分配的唯一值就会在每个Vuser的所有接下来的迭代中使用。

    请确保表格中的数据对所有的Vuser和它们的迭代来说是充足的。如果拥有20个Vuser,并且要运行5次迭代,则表格中必须至少包含有100个唯一值。

    如果数据表格中没有足够的值,可以在"When out of value"下拉框中指示VuGen如何继续运行:"中断Vuser"、"以循环方式继续"或者"使用最后的值继续"。如果选择"使用最后的值"继续运行,则Vuser将会为所有接下来的迭代使用表格中最后一行的数据。

    如果想要给每一个Vuser都分配值,并且不想让那些值在Vuser之间共享,要实现该目标,可以在图3-25中的"Allocate Vuser values in the controller"(在控制台中分配Vuser值)组合框中指示VuGen为每个Vuser的值分配一个特定的编号。默认情况下,VuGen自动为Vuser的值分配必需的编号。

    要跟踪上述说的分配编号情况,请启用日志运行时设置中的"扩展日志">"参数替换"选项。当没有足够的数据时,VuGen将会向Vuser日志中写入警告消息:"在表<表名>中,此参数没有其他唯一值"。

    注意:

    使用该类型必须注意数据表有足够多的数。比如,控制台中设定20个Vuser进行5次循环,那么编号为1的Vuser取前5个数,编号为2的Vuser取6~10的数,依此类推,这样数据表中至少要有100个数据,否则控制台运行过程中会返回一个错误。

    假如你的代码是这样的:
       
              web_submit_form("reservations.pl",
                    "Name=depart", "Value=
    {depart_city}", ENDITEM,
                    "Name=departDate", "Value=06/20/2007", ENDITEM,
                    LAST);

            web_submit_form("reservations.pl_2",
                   
          "Name=depart", "Value={depart_city}", ENDITEM,
                    "Name=reserveFlights.x", "Value=81", ENDITEM,
                    LAST);
    再假设参数列表中这个参数depart_city的值是:上海
                                                                   
    北京
                                                                   
    重庆
                          西安
                          合肥

    这段代码中两个地方都用到了{depart_city}, 关于这个参数的调用是如何的呢?关键取决于你自己在参数列表中对于这个参数的设置。
    假如你的设置是:
      A. update value ōn=each occurrence
          
    在第一个循环中,第一段代码web_submit_form("reservations.pl"....... depart_city="上海"
              第二段代码web_submit_form("reservations.pl_2".....depart_city="北京"

          
    在第二个循环中,第一段代码web_submit_form("reservations.pl"....... depart_city="重庆"
              第二段代码web_submit_form("reservations.pl_2".....depart_city="西安"
         
          
    在第三个循环中,第一段代码web_submit_form("reservations.pl"....... depart_city="合肥"
          ........................................................................
          
    如果参数不够用的时候,怎么办呢?那就看你参数列表中另外一个设置when out of value怎么设置呢? 这里先不谈。

      B. update value ōn=each iteration
          
    在第一个循环中,第一段代码web_submit_form("reservations.pl"....... depart_city="上海"
              第二段代码web_submit_form("reservations.pl_2".....depart_city="上海"

          
    在第二个循环中,第一段代码web_submit_form("reservations.pl"....... depart_city="北京"
              第二段代码web_submit_form("reservations.pl_2".....depart_city="北京"
         
          
    在第三个循环中,第一段代码web_submit_form("reservations.pl"....... depart_city="重庆"
          ..............................................................................

      C. update value ōn=once
          
    在第一个循环中,第一段代码web_submit_form("reservations.pl"....... depart_city="上海"
              第二段代码web_submit_form("reservations.pl_2".....depart_city="上海"

          
    在第二个循环中,第一段代码web_submit_form("reservations.pl"....... depart_city="上海"
              第二段代码web_submit_form("reservations.pl_2".....depart_city="上海"
         
          
    在第三个循环中,第一段代码web_submit_form("reservations.pl"....... depart_city="上海"

  • (转)LR之关联

    2008-12-29 09:57:49

    1.什么是关联?

    关联是为了获取每次运行脚本的唯一数据值和通过嵌套查询生成的数据。关联提供了避免产生重复数据错误的数值以及优化代码(以避免嵌套查询)。关联是正常回放含有动态数据如Session IDs,Database Primary Keys 和差不多所有的HTTP安全机制脚本的根本。关联的目的就是吧脚本中某些hard-coded数据转变成从服务器传过来的动态的,每次执行都不一样的数据。

    2.参数(化)和关联的区别

    参数(化)相当于代码编写中的变量。是某个变量向服务器输入不同的值,用来模拟真实的用户。运行脚本时,不同的数据集被发送给服务器。只能对某个具体的变量值进行参数化。参数化的对象在回放过程中即时没有被参数化也不会报错,只是像服务器输入了相同的值。但是关联的对象在回放过程中如果没有做关联,回放过程中就会报错。关联是对系统的动态数据(每次运行脚本都会变化的值,是从服务器传过来的)进行。简单的说,每一次执行时都会变动的值,就有可能需要做关联。

    3.动态关联和手工关联的区别

    动态关联是我们为关联设置规则,可以是具体的应用程序服务,这里的数据由所创建的规则替代。在手工关联中,我们想要关联的数值被扫描并且编写关联函数完成关联。VuGen内建自动关联引擎(auto-correlation engine),可以自动找出需要关联的值,并可以利用关联函数自动建立关联。

    手动关联需要自行查找关联的对象,然后自行插入关联函数。

    4.如何发现哪里需要关联?

    两种方式:首先回放扫描不同的值然后看哪些值需要关联。其次,我们可以录制2个脚本然后作比较。我们可以查看不同的文件决定需要关联的数据。在我实践的某个项目中,为每个用户提供一个唯一的ID,一个不确定的数字,是自动生成的,有序且值唯一。我需要关联这个ID值以防止在运行脚本是出现错误。我用的是扫描的方式关联。

    5.在哪里设置自动关联选项?

    网页自动关联可以在recording options -->correlation tab栏设置。这里可以为全部脚本设置关联并选择是在线问题信息还是离线actions,我们也可为这些关联定义规则。数据库的自动关联可以用输出窗口、关联扫描、找关联查询项并选择要关联的查询值。如果知道需要关联的具体值,只需要为这些值创建关联并指定这些值是如何创建的。

    6. 在网页录制脚本中,什么函数能捕获动态数据?

    Web_reg_save_param函数可以将动态数据信息保存到一个参数中。

    Web_reg_save_param函数语法:

    int web_reg_save_param (const char *mpszParamName, <List of Attributes>, LAST);

    以下表格列出了可获取到的属性. 注意属性值字符串没有大小写区分(例如:Search=all)

    NotFound

    边界找不到或空字符串生成时的处理方法。默认值为“Error”,说明当边界值找不到时,VuGen可以作为一个错误提出。当设置为“EMPTY”,没有错误信息提出脚本继续执行。注意:如果脚本设置了Continue on Error项,则当边界值没有找到时,脚本也会继续执行,但会早Extend log文件中输出一个错误信息

    LB

    参数或动态数据的左边界。该参数必须是非空字符串。区分大小写。如果想忽略大小写,则用LB/IC。如果要指定二进制数据用LB/BIN

    RB

    参数或动态数据的右边界。该参数必须是非空字符串。区分大小写。如果不想区分大小写,则用RB/IC。如果要指定二进制数据用RB/BIN

    RelFrameID

    相对于请求的URL,HTML页面的层次(hierarchy level)。可以是All或者是一个数字

    Search

    查询的范围—去哪里查看分割数据。可选值有:Headers (search only the headers), Body (search only Body data, not headers), or ALL (search Body and headers)。默认值是ALL。

    ORD

    可选参数。指定匹配项的顺序或出现数(the ordinal or occurrence number of the match)。默认值为1,如果指定是“ALL”,则将参数值保存在一个数值里。

    SaveOffset

    The offset of a sub-string of the found value, to save to the parameter. The default is 0. The offset value must be non-negative.

    Savelen

    The length of a sub-string of the found value, from the specified offset, to save to the parameter. The default is -1, indicating until the end of the string.

    Convert

    The conversion method to apply to the data:

    HTML_TO_URL: convert HTML-encoded data to a URL-encoded data format

    HTML_TO_TEXT: convert HTML-encoded data to plain text format

    7.HTML页面中的动态数据可能存在于:

            每次获取相关网页都变化的URL

            在form提交过程中录制的字段(有时是隐藏的)

            JavaScritpt cookies

    第1种情况:

    录制时,假设点击 “buy me now!”文字的超链接,VuGen录制的URL是:http://host//cgi-bin/purchase.cgi?date=170397&ID=1234因为date "170397"和 ID "1234"是在录制过程中自动生成的,每一次新的浏览会话重新生成新的date和ID。当运行脚本时,“Buy me now!”链接的URL不再是录制时的URL而是一个新的了。因此,Web服务器不能重新获得URL。

    第2种情况

    考虑一种情形:提交一个用户填写了他的姓名和帐号ID的form。当这个form提交时,一个唯一的序列号和该用户的数据同时也一起提交给了服务器。这个序列号是HTML代码中一个隐藏字段的值,被VuGen录制到了脚本中。因为这个序列号在每次浏览会话中都会变,所以Vuser不能成功回放录制的脚本。

    8.如果右界不一致,指定一个右边界是不够的,需要指定可选右边界。因为它不一致---例如有时是”@”有时是“&”。这种情况下,指定&为可选择的右边界。

  • (转)如何在 LoadRunner 脚本中做关联 (Correlation)

    2008-12-29 09:50:07

     当录制脚本时,VuGen会拦截client端(浏览器)与server端(网站服务器)之间的对话,并且通通记录下来,产生脚本。在VuGen的Recording Log中,您可以找到浏览器与服务器之间所有的对话,包含通讯内容、日期、时间、浏览器的请求、服务器的响应内容等等。脚本和Recording Log最大的差别在于,脚本只记录了client端要对server端所说的话,而Recording Log则是完整纪录二者的对话。   当执行脚本时,您可以把VuGen想象成是一个演员,它伪装成浏览器,然后根据脚本,把当初真的浏览器所说过的话,再对网站伺服器重新说一遍,VuGen企图骗过服务器,让服务器以为它就是当初的浏览器,然后把网站内容传送给VuGen。
      所以纪录在脚本中要跟服务器所说的话,完全与当初录制时所说的一样,是写死的(hard-coded)。这样的作法在遇到有些比较聪明的服务器时,还是会失效。这时就需要透过「关联(correlation)」的做法来让VuGen可以再次成功地骗过服务器。
    何谓关联(correlation)?
      所谓的关联(correlation)就是把脚本中某些写死的(hard-coded)数据,转变成是撷取自服务器所送的、动态的、每次都不一样的数据。
      举一个常见的例子,刚刚提到有些比较聪明的服务器,这些服务器在每个浏览器第一次跟它要数据时,都会在数据中夹带一个唯一的辨识码,接下来就会利用这个辨识码来辨识跟它要数据的是不是同一个浏览器。一般称这个辨识码为Session ID。对于每个新的交易,服务器都会产生新的Session ID给浏览器。这也就是为什么执行脚本会失败的原因,因为VuGen还是用旧的Session ID向服务器要数据,服务器会发现这个Session ID是失效的或是它根本不认识这个Session ID,当然就不会传送正确的网页数据给VuGen了。
      下面的图示说明了这样的情形:
      当录制脚本时,浏览器送出网页A的请求,服务器将网页A的内容传送给浏览器,并且夹带了一个ID=123的数据,当浏览器再送出网页B的情求时,这时就要用到ID=123的数据,服务器才会认为这是合法的请求,并且把网页B的内容送回给浏览器。
    在执行脚本时会发生什么状况?浏览器再送出网页B的请求时,用的还是当初录制的ID=123的数据,而不是用服务器新给的ID=456,整个脚本的执行就会失败。
      要对付这种服务器,我们必须想办法找出这个Session ID到底是什么、位于何处,然后把它撷取下来,放到某个参数中,并且取代掉脚本中有用到Session ID的部份,这样就可以成功骗过服务器,正确地完成整个交易了。
      哪些错误代表着我应该做关联(correlation)?
    假如脚本需要关联(correlation),在还没做之前是不会执行通过的,也就是说会有错误讯息发生。不过,很不幸地,并没有任何特定的错误讯息是和关联(correlation)有关系的。会出现什么错误讯息,与系统实做的错误处理机制有关。错误讯息有可能会提醒您要重新登入,但是也有可能直接就显示HTTP 404的错误讯息。
      要如何做关联(correlation)?
      关联(correlation)函数
      关联(correlation)会用到下列的函数:
    • web_reg_save_param:这是最新版,也是最常用来做关联(correlation)的函数。
    语法:
    web_reg_save_param ( “Parameter Name” , < list of Attributes >, LAST );
    • web_create_html_param、web_create_html_param_ex:这二个函数主要是保留作为向前兼容的目的的。建议使用 web_reg_save_param 函数。
    详细用法请参考使用手册。在VuGen中点选【Help】>【Function reference】>【Contexts】>【Web and Wireless Vuser Functions】>【Correlation Functions】。
    如何找出要关联(correlation)数据
    简单的说,每一次执行时都会变动的值,就有可能需要做关联(correlation)。
    VuGen提供二种方式帮助您找出需要做关联(correlation)的值:
    1. 自动关联
    2. 手动关联
    自动关联
    VuGen内建自动关联引擎(auto-correlation engine),可以自动找出需要关联的值,并且自动使用关联函数建立关联。
    自动关联提供下列二种机制:
    • Rules Correlation:在录制过程中VuGen会根据订定的规则,实时自动找出要关联的值。规则来源有两种:
    o 内建(Built-in Correlation):
    VuGen已经针对常用的一些应用系统,如AribaBuyer、BlueMartini、BroadVision、InterStage、mySAP、NetDynamics、Oracle、PeopleSoft、Siebel、SilverJRunner等,内建关联规则,这些应用系统可能会有一种以上的关联规则。您可以在【Recording Options】>【Internet Protocol】>【Correlation】中启用关联规则,则当录制这些应用系统的脚本时,VuGen会在脚本中自动建立关联。
    您也可以在【Recording Options】>【Internet Protocol】>【Correlation】检视每个关联规则的定义。
    o 使用者自订(User-defined Rules Correlation):
    除了内建的关联规则之外,使用者也可以自订关联规则。您可以在【Recording Options】>【Internet Protocol】>【Correlation】建立新的关联规则。
    • Correlation Studio:有别于Rules Correlation,Correlation Studio则是在执行脚本后才会建立关联,也就是说当录制完脚本后,脚本至少须被执行过一次,Correlation Studio才会作用。Correlation Studio会尝试找出录制时与执行时,服务器响应内容的差异部分,藉以找出需要关联的数据,并建立关联。
    Rule Correlation
    请依照以下步骤使用Rule Correlation:
    1. 启用auto-correlation
    1. 点选VuGen的【Tools】>【Recording Options】,开启【Recording Options】对话窗口,选取【Internet Protocol】>【Correlation】,勾选【Enable correlation during recording】,以启用自动关联。
    2. 假如录制的应用系统属于内建关联规则的系统,如AribaBuyer、BlueMartini、BroadVision、InterStage、mySAP、NetDynamics、Oracle、PeopleSoft、Siebel、SilverJRunner等,请勾选相对应的应用系统。
    3. 或者也可以针对录制的应用系统加入新的关联规则,此即为使用者自订的关联规则。
    4. 设定当VuGen侦测到符合关联规则的数据时,要如何处理:
     【Issue a pop-up message and let me decide online】:跳出一个讯息对话窗口,询问您是否要建立关联。
     【Perform. correlation in sceipt】:直接自动建立关联
    2. 录制脚本
    开始录制脚本,在录制过程中,当VuGen侦测到符合关联规则的数据时,会依照设定建立关联,您会在脚本中看到类似以下的脚本,此为BroadVision应用系统建立关联的例子,在脚本批注部分可以看到关联前的数据为何。
    3. 执行脚本验证关联是OK的。
    Correlation Studio
    当录制的应用系统不属于VuGen预设支持的应用系统时,Rule Correlation可能既无法发挥作用,这时可以利用Correlation Studio来做关联。
    Correlation Studio会尝试找出录制时与执行时,服务器响应内容的差异部分,藉以找出需要关联的数据,并建立关联。
    使用Correlation Studio的步骤如下:
    1. 录制脚本并执行
    2. 执行完毕后,VuGen会跳出下面的【Scan Action for Correlation】窗口,询问您是否要扫描脚本并建立关联,按下【Yes】按钮。
    3. 扫描完后,可以在脚本下方的【Correlation Results】中看到扫描的结果。
    4. 检查一下扫瞄的结果后,选择要做关联的数据,然后按下【Correlate】按钮,一笔一笔做,或是按下【Correlate All】让VuGen一次就对所有的数据建立关联。
    注意:由于Correlation Studio会找出所有有变动的数据,但是并不是所有的数据都需要做关联,所以不建议您直接用【Correlate All】。
    5. 一般来说,您必须一直重复步骤1~4直到所有需要做关联的数据都找出来为止。因为有时前面的关联还没做好之前,将无法执行到后面需要做关联的部份。
    有可能有些需要做关联的动态数据,连Correlation Studio都无法侦测出来,这时您就需要自行做手动关联了。
    手动关联
    手动关联的执行过程大致如下:
    1. 使用相同的业务流程与数据,录制二份脚本
    2. 使用WinDiff工具协助找出需要关联的数据
    3. 使用web_reg_save_param函数手动建立关联
    4. 将脚本中有用到关联的数据,以参数取代
    接下来将详细的说明如何执行每个步骤
    使用相同的业务流程与数据,录制二份脚本
    1. 先录制一份脚本并存档。
    2. 依照相同的操作步骤与数据录制第二份脚本并存盘。注意,所有的步骤和输入的数据一定都要一样,这样才能找出由服务器端产生的动态数据。
    有时候会遇到真的无法使用相同的输入数据,那您也要记住您使用的输入数据,到时才能判断是您输入的数据,还是变动的数据。
    使用WinDiff工具协助找出需要关联的数据
    1. 在第二份脚本中,点选VuGen的【Tools】>【Compare with Vuser…】,并选择第一份脚本。
    2. 接着WinDiff会开启,同时显示二份脚本,并显示有差异的地方。WinDiff会以一整行黄色标示有差异的脚本,并且以红色的字体显示真正差异的文字。(假如没看到红色字体,请点选【Options】>【View】>【Show Inline Differences】)。
    3. 逐一检视二份脚本中差异的部份,每一个差异都可能是需要做关联的地方。选取差异的脚本,然后复制。
    在复制时,有时并不需要取整行脚本,可能只会选取脚本中的一部分。
    注意:请忽略lr_thik_time的差异部份,因为lr_thik_time是用来模拟每个步骤之间使用者思考延迟的时间。
    4. 接着要在Recording Log(单一protocol)或是Generation Log(多重protocol)中找这个值。将鼠标光标点到Recording Log的第一行开头,按下Ctrl+F,开启【Find】窗口,贴上刚刚复制的脚本,找出在Recording Log第一次出现的位置。
    结果会有二种:
    o 在Recording Log中找不到要找的数据,这时请先确认您找对了脚本,毕竟现在开启了二个几乎一样的脚本,很容易弄错。
    o 在Recording Log中找到了要找的数据,这时要确认数据是从服务器端传送过来的。首先可以先检查数据的标头,从标头的Receiving response可以知道数据是从服务器端传送到client端的。假如此数据第一次出现是在Sending request中,则表示此数据是由client端产生,不需要做关联,但是有可能需要做参数化(parameterized)。
    您要找的标头格式如下:
    *** [tid=b9 Action1 2] Receiving response from host astra.merc-int.com:80 ( 25/11/2002 12:04:00 )
    5. 现在您已经找到录制二次都不一样,而且是由服务器所产生的动态数据了,而此数据极有可能需要做关联。
    使用web_reg_save_param函数手动建立关联
    在找到是由服务器所产生的动态数据之后,接下来要做的就是找出适当的位置,使用web_reg_save_param函数,将这个动态数据撷取到某个参数中。
    1. 要在哪里使用web_reg_save_param函数?
    在之前的步骤,我们已经在Execution Log找到可能需要关联的动态数据。在Execution Log中选取动态数据前的文字然后复制,我们将会利用这段文字,来帮助我们找出要关联的动态数据。
    不过在这之前我们要先找出使用web_reg_save_param函数的正确位置,所以我们要再重新执行一遍脚本,而且这次会开启所有的Log。
    1. 在VuGen中点选【Vuser】>【Run-Time Settings】。
    2. 点选【General】>【Log】。
    3. 勾选【Enable logging】、【Always sends messages】、【Extended log】,以及【Extended log】下的所有选项。
    4. 按下【OK】就可以执行脚本了。
    执行完脚本之后,在Execution Log中搜寻刚刚复制的字符串。找到字符串后,在字符串前面会有A.tion1.c(7),这个7就是到时候要插入web_reg_save_param函数的位置,也就是要插入到脚本的第7行。
    在脚本的第7行前插入一行空白行,然后输入
    web_reg_save_param(“UserSession”,
    “UserSession” 这个 “UserSession” 就是到时要使用的参数名称,建议给个有意义的名字。
    注意:到这里整个web_reg_save_param函数还没完成。
    2. 找出web_reg_save_param中要用到的边界
    web_reg_save_param函数主要是透过动态数据的前面和后面的固定字符串,来辨识要撷取的动态数据的,所以我们还需要找出动态数据的边界字符串。
    找出左边界字符串
    再回到Execution Log中,选取动态数据前的字符串并且复制它。
    这时会有个问题,到底要选取多少字符串才足以唯一识别要找的动态数据呢?建议是越多越好,但是尽量不要包含到特殊字符。
    在这边我们选取「input type=hidden name=userSession value=」字符串。选好之后,还要再确认一次这段字符串真的是可以唯一识别的,所以我们在Execution Log中透过Ctrl+F的搜寻,找找看这段字符串是否可以找到要找的动态数据。假如找不到,web_reg_save_param函数还有个ORD参数可以使用,ORD参数可以设定出现在第几次的字符串才是要找的字符串。
    将这个边界字符串加到未完成的web_reg_save_param函数中:
    web_reg_save_param(“UserSession”, “LB= input type=hidden name=userSession value=”,
    找出右边界字符串
    接下来要找出动态数据的右边界字符串,这个字符串就比较好找了,从动态数据的最后一个字符开始,通常就是我们要找的右边界字符串了。
    以这个例子来看,就是「>」,所以再把右边界字符串加入,web_reg_save_param函数中,这时web_reg_save_param函数已经快完成了。最后再加上「LAST);」就完成整个web_reg_save_param函数了。
    web_reg_save_param(“UserSession”, “LB= input type=hidden name=userSession value=”, “RB=>”, LAST);
    将脚本中有用到关联的数据,以参数取代
    当使用web_reg_save_param建立参数后,接下来就是用“UserSession”参数去取代脚本中写死的(hard-coded)资料。
    范例:

    “Name=userSession”, “Value=75893.0884568651DQADHfApHDHfcDtccpfAttcf”, ENDITEM,
    换成
    “Name=userSession”, “Value={UserSession}”, ENDITEM,
    到这里您已经完成了一个关联了,接下来就是执行脚本,是否能成功运行,假如还是有问题,就要检查看看是否还需要再做另一个关联。
    关于 web_reg_save_param 函数
    对于关联(correlation)来说,web_reg_save_param是最重要的一个函数,其功能是在下载的网页内容中,透过设定的边界字符串,找出特定的数据并将其储存在一个参数中,以供后续脚本使用。
    接下来将针对web_reg_save_param做比较详细的说明。
    Service and registration type function
    web_reg_save_param是一个Service function。service function主要是用来完成一些特殊的工作的,如关联、设定proxy、提供认证信息等,当其作用时,不会对网页的内容做任何的修改。
    web_reg_save_param同时也是一个registration type function (只要函数名称中包含_reg_的字眼,表示其为registration type function)。registration type function意味着其真正作用的时机是在下一个action function完成时执行的。举例来说,当某个web_url执行时所接收到的网页内容中包含了要做关联的动态数据,则必须将web_reg_save_param放在此web_url之前,则web_reg_save_param会在web_url执行完毕后,也就是网页内容都下载完后,再执行web_reg_save_param找寻要做关联的动态数据并建立参数。
    所以要记住一点,要使用registration type function时,要注意其放置的位置必须在要作用的action function之前。
    语法
    int web_reg_save_param(const char *ParamName, <list of Attributes>, LAST);
    参数说明
    ParamName:存放动态数据的参数名称
    list of Attributes:其它属性,包含 Notfound, LB, RB, RelFrameID, Search, ORD, SaveOffset, Convert, 以及 SaveLen。属性值不分大小写,例如 Search=all。以下将详细说明每个属性值的意义:
    • Notfound:指定当找不到要找的动态数据时该怎么处置。
    o Notfound=error:当找不到动态数据时,发出一个错误讯息。假如没设定此属性,此为LoadRunner的默认值。
    o Notfound=warning:当找不到动态数据时,不发出错误讯息,只发出警告,脚本也会继续执行下去不会中断。在对角本除错时,可以使用此属性值。
    • LB:动态数据的左边界字符串。此属性质是必须要有的,而且区分大小写。
    • RB:动态数据的右边界字符串。此属性质是必须要有的,而且区分大小写。
    • RelFrameID:相对于URL而言,欲搜寻的网页的Frame。此属性质可以是All或是数字,而且可有可无。
    • Search:搜寻的范围。可以是Headers(只搜寻headers)、Body(只搜寻body部分,不搜寻header)、Noresource(只搜寻body部分,不搜寻header与resource)或是All(搜寻全部范围,此为默认值)。此属性质可有可无。
    • ORD:指明从第几次出现的左边界开始才是要撷取的数据。此属性质可有可无,默认值是1。假如值为All,则所有找到符合的数据会储存在数组中。
    • SaveOffset:当找到符合的动态数据时,从第几个字符开始才开始储存到参数中。此属性质不可为负数,其默认值为0。
    • Convert:可能的值有二种:
    o HTML_TO_URL: 将HTML-encoded数据转成URL-encoded数据格式
    o HTML_TO_TEXT:将HTML-encoded数据转成纯文字数据格式
    • SaveLen:从offect开始算起,到指定的长度内的字符串,才储存到参数中。此参数可有可无,默认值是-1,表示储存到结尾整个字符串。
    范例
    web_reg_save_param("A", "LB/ic=<a href=", "RB='>", "Ord=All", LAST);nner会搜寻网页中所有以 「<a href=」 开头,且以 「’>」结束,当中包含的字符串,并且储存在「A」参数中。
    Tips and Tricks
    以下提供一些关联的常见问题:
    • 如何打印出参数值?
    lr_output_message这二个函数来做到。例如:
    lr_output_message(“Value Captured = %s”, lr_eval_string(“{ParameterName}”));
    lr_eval_string与lr_output_message函数的使用说明请参考LoadRunner Online Function Reference。
    • 在脚本的data目录下找不到路制时的快照(snapshot)
    造成在脚本的data目录下找不到路制时的快照(snapshot)的可能原因如下:
    o 脚本是由VuGen 6.02或更早的版本所录制的
    o 汇入的Action不会包含快照(snapshot)的档案
    o 脚本是储存在只读的目录下,早成VuGen无法储存执行时撷取的快照(snapshot)
    o 某些步骤并不会产生快照(snapshot),如浏览某个资源
    o 快照(snapshot)功能被取消
    【Tools】>【General options】>【Correlation】tab >【Save correlation information during replay】
    • 开启WinDiff时出现「File no longer available」的错误讯息
    WinDiff这个工具有些限制,无法开启包含空格符的目录或是脚本,所以建议命名时不要使用空格符,并且尽可能将名称取短一点。
    • 录制时突然跳出【Correlation warning】对话窗口
    当你有勾选自动关联的【Issue a popup message and let me decide online】选项,当VuGen发现有可能要做关联的数据时,就会跳出【Correlation warning】的窗口,询问你要做关联(Correlation in scrīpt)还是要忽略(Ignore)。
    另外你也可以勾选【Perform. correlation in scrīpt】,让VuGen自动作关联,不会再跳出询问窗口。
    或是勾选【Disable correlation engine】,关闭自动关联的功能。

    • 如何手动启动「Scan action for correlation」的功能
    要手动启动「Scan action for correlation」的功能,请先执行脚本一次后,点选【Vuser】>【Scan Action for Correlation】。

    • 执行完脚本后并未出现【Scan Action for Correlation】窗口
    要启用【Scan Action for Correlation】功能,请点选【Tools】>【General options】>【Correlation】tab,勾选【Show Scan for correlation popup after replay of Vuser】选项。
613/4<1234>
Open Toolbar