3.3
语句关联
当录制脚本时,VuGen会拦截客户端(浏览器)与服务器端(网站服务器)之间的会话,并且记录下来,产生脚本。在VuGen的Recording
Log中,可以找到浏览器与服务器之间所有的对话,包含通信内容、日期、时间、浏览器的请求、服务器的响应内容等等。脚本和Recording Log最大的差别在于,脚本只记录了客户端要对服务器端所说的话,而Recording Log则是完整记录二者的对话。
当执行脚本时,可以把VuGen想象成是一个演员,它伪装成浏览器,然后根据脚本,把当初浏览器确实说过的话,再对网站服务器重新说一遍,VuGen企图骗过服务器,让服务器以为它就是当初的浏览器,然后把网站内容传送给VuGen。
所以VuGen记录在脚本中的要跟服务器所说的话,完全与当初录制脚本时所说的一样,是写死的(hard-coded)。这样的做法在遇到有些比较聪明的服务器时,还是会失效。这时就需要通过关联来让VuGen再次成功地骗过服务器。
3.3.1 关联的意义
所谓的关联就是把脚本中某些写死的代码(hard-coded)数据,转变成撷取自服务器所送的、动态的、每次都不一样的数据。
一般情况下,比较聪明的服务器在每个浏览器第一次跟它要数据时,
都会在数据中夹带一个唯一的辨识码,接下来就会利用这个辨识码来辨识跟它要数据的是不是同一个浏览器,一般称这个辨识码为Session
ID。对于每个新的请求,服务器都会产生新的Session ID给浏览器。这也就是执行脚本会失败的原因,因为VuGen还是用旧的Session
ID向服务器要数据,服务器发现这个Session ID是失效的或者它根本不认识这个Session
ID,当然就不会传送正确的网页数据给VuGen了。
下面的例子说明了这样的情形:
当录制脚本时,浏览器发出对网页A的请求,服务器将网页A的内容传送给浏览器,并且夹带了一个ID=123的数据,当浏览器再发出对网页B的请求时,这时就要用到ID=456的数据,服务器才会认为这是合法的请求,并且把网页B的内容送回给浏览器。
在执行脚本时会发生什么状况呢?浏览器再发出对网页B的请求时,用的还是当初录制的ID=123的数据,而不是用服务器新给的ID=456,因此整个脚本的执行就会失败。
要对付这种服务器,必须想办法找出这个Session ID到底是什么、位于何处,然后把它撷取下来,放到某个参数中,并且取代脚本中有用到Session ID的部分,这样就可以成功骗过服务器,正确地完成整个交易了。
1.什么地方需要关联
凡是脚本每次执行时都必须获得唯一标识的地方都需要关联。假如脚
本需要关联,如果不做关联是不会执行通过的,也就是说会有错误消息发生。不过很遗憾,并没有任何特定的错误消息是和关联有关系的。会出现什么错误消息,与
系统实际的错误处理机制有关。错误消息有可能会提醒用户要重新登录,但是也有可能直接就显示HTTP 404的错误消息。
2.如何做关联
关联会用到下列的函数:
Ÿ
web_reg_save_param;
Ÿ
web_create_html_param;
Ÿ
web_create_html_param_ex;
其中,web_reg_save_param的语法为:
web_reg_save_param (
"Parameter Name" , < list of Attributes >, LAST );
web_create_html_param和web_create_html_param_ex这两个函数主要是保留以兼容以前旧版本。建议使用web_reg_save_param函数。
那么,如何找出要关联数据呢?简单地说,每一次执行时都会变动的值,就有可能需要做关联。VuGen提供两种方式帮助用户找出需要做关联的值:自动关联和手动关联。
3.3.2 自动关联方法
VuGen内建自动关联引擎(Auto-correlation Engine),提供Rules
Correlation和Correlation Studio两种机制,可以自动找出需要关联的值,并且自动使用关联函数建立关联。
1.“Rules
Correlation”:在录制过程中VuGen会根据使用者事先制订的规则,实时自动找出要关联的值。规则的来源有内建(Built-in
Correlation)和使用者自定(User-defined Rules Correlation)关联规则两种。
Ÿ
内建(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”检视每个关联规则的定义。
Ÿ
除了内建的关联规则之外,使用者也可以自定关联规则。可以在“Recording Options”>“Internet
Protocol”>“Correlation”建立新的关联规则。
请依照以下步骤使用“Rule Correlation”:
单击VuGen的“Tools”>“Recording
Options”,开启“Recording Options”对话窗口,选取“Internet
Protocol”>“Correlation”,勾选“Enable correlation during
recording”,以启用自动关联。
假如录制的应用系统属于内建关联规则的系统,如
AribaBuyer、BlueMartini、BroadVision、InterStage、mySAP、NetDynamics、Oracle、
PeopleSoft、Siebel、SilverJRunner等,请勾选相对应的应用系统。或者也可针对录制的应用系统加入新的关联规则,此即为使用
者自定的关联规则。
自动关联时VuGen会侦测到符合关联规则的数据,以下为处理方式:
首先会跳出一个“Correlation
warning”消息对话窗口,选择“Issue a pop-up message and let me decide
online”:询问用户是否要建立关联,每遇到一次询问一次,以了解每个关联数据的内容和位置。如果每次询问很麻烦,可以选择“Perform
correlation in script”(直接自动建立关联)。
2.“Correlation
Studio”:有别于“Rules Correlation”,“Correlation
Studio”是在执行脚本后才会建立关联,也就是说当录制完脚本后,脚本至少须被执行过一次时“Correlation
Studio”才会起作用。“Correlation
Studio”会尝试找出录制时与执行时,服务器响应内容的差异部分,藉以找出需要关联的数据,并建立关联。
当录制的应用系统不属于VuGen预设支持的应用系统时,“Rule Correlation”可能无法发挥作用,这时可以利用“Correlation Studio”来进行关联。
使用“Correlation Studio”的步骤如下:
(1)录制脚本并执行。
(2)执行完毕后,VuGen会跳出“Scan Action for Correlation”窗口,询问用户是否要扫描脚本并建立关联,单击“Yes”按钮,扫描脚本。
(3)扫描完后,可以在脚本下方的“Correlation Results”中看到扫描的结果。
(4)检查一下扫描的结果,选择要做关联的数据,然后单击“Correlate”按钮,逐次关联,或是单击“Correlate All”让VuGen一次就对所有的数据建立关联。
由于Correlation Studio会找出所有有变动的数据,但是并不是所有的数据都需要做关联,所以不建议用户直接用“Correlate All”。
重复步骤(1)~(4),直到所有需要做关联的数据都找出来为止。
有时关联的地方有多处,前面的关联如果没有执行通过,执行将停止验证脚本的正确性,后面需要做关联的部分无法被扫描出来。
3.3.3 手动关联方法
在对脚本进行关联的时候,有的脚本利用上面介绍的方法自动关联就可以了,但是也有可能某些需要做关联的动态数据,连“Correlation Studio”都无法侦测出来,这时就需要进行手动关联。
虽然手动关联比自动关联方法麻烦一些,操作复杂,对于没有代码编程经验的测试初学者来说,甚至有时连需要关联的位置都无法找到,但是经过多次实践后,会发现很多关联的方法与技巧。毕竟手动关联出来的脚本拥有更大的灵活性,可以随意改动来满足用户不同的需求。
手动关联的执行过程大致如下:
Ÿ
使用相同的业务流程与数据,录制两份脚本。
Ÿ
使用WinDiff工具协助找出需要关联的数据。
Ÿ
使用web_reg_save_param函数手动建立关联。
Ÿ
将脚本中有用到关联的数据,以参数取代。
具体的执行过程如下:
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(单一协议)或是Generation Log(多重协议)中找这个值。将鼠标光标放到Recording
Log的第一行开头,按下“Ctrl+F”组合键,开启“Find”窗口,贴上刚刚复制的脚本,找出其在Recording Log第一次出现的位置。
如果在Recording Log中找不到要找的数据,这时请先确认是否找对了脚本,毕竟现在开启了两个几乎一样的脚本,很容易弄错。
如果在
Recording Log中找到了要找的数据,这时要确认数据是否为从服务器端传送过来的。首先可以检查数据的标头,从标头的Receiving
response可以知道数据是否是从服务器端传送到客户端的。假如此数据第一次出现是在Sending
request中,则表示此数据是由客户端产生,不需要做关联,但是有可能需要做参数化(Parameterized)。
现在已经找到录制两次不一致而且是由服务器所产生的动态数据,此数据极有可能需要做关联。
3.使用web_reg_save_param函数手动建立关联。
在找到由服务器所产生的动态数据之后,接下来要做的就是找出适当的位置,使用web_reg_save_param函数,将这个动态数据撷取到某个参数中。
(1)web_reg_save_param函数
对于关联来说,web_reg_save_param是最重要的一个函数,其功能是在下载的网页内容中,通过设定的边界字符串,找出特定的数据并将其存储在一个参数中,以供后续脚本使用。
web_reg_save_param是一个服务端函数(Service function,主要用来完成一些特殊的工作,如关联、设定proxy、提供认证信息等),当其作用时,不会对网页的内容做任何的修改。
web_reg_save_param
同时也是一个注册类型的函数(Registration Type
Function,只要函数名称中包含_reg_的字眼,表示其为注册类型的函数)。注册类型的函数意味着其真正作用的时机是在下一个动作函数
(Action
Function)完成时。举例来说,当某个web_url执行时所接收到的网页内容中包含了要做关联的动态数据,则必须将
web_reg_save_param放在此web_url之前,web_reg_save_param会在web_url执行完毕后,也就是网页内容都
下载完后,再执行web_reg_save_param,寻找要做关联的动态数据并建立参数。
要记住一点,当使用注册类型的函数时,要注意其放置的位置必须在要作用的动作函数之前。
(2)web_reg_save_param的语法
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”。下面将详细说明每个属性值的意义。
Ø Notfound:指定当找不到要找的动态数据时该怎么处理。
当指定Notfound=error时,表示着找不到动态数据时,就发出一个错误消息。此为该属性的默认值。
当指定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:转换数据格式。当指定该属性值为HTML_TO_URL时,意味着将HTML-encoded数据转成URL-encoded数据格式。如果是HTML_TO_TEXT,表示将HTML-encoded数据转成纯文字数据格式。
Ø SaveLen:当找到匹配项后,偏移量之后的几个字元存储到参数中。此参数可有可无,默认值是-1,表示一直到结尾的整个字符串都存入参数中。
(3)确定使用web_reg_save_param函数的位置
之前的步骤已经在
Execution Log中找到可能需要关联的动态数据。在Execution
Log中选取动态数据前的文字,然后复制,利用这段文字,找出要关联的动态数据。不过在这之前,需要先找出使用web_reg_save_param函数
的正确位置,所以要再重新执行一遍脚本,而且这次会开启所有的Log。
在VuGen中单击
“Vuser”>“Run-Time Settings”。单击“General”>“Log”,勾选“Enable
logging”、“Always sends messages”、“Extended log”以及“Extended
log”下的所有选项。然后,单击“OK”按钮就可以执行脚本了。
执行完脚本之后,在Execution Log中搜寻刚刚复制的字符串。找到字符串后,在字符串前面会有A.tion1.c(7),这个7就是到时候要插入web_reg_save_param函数的位置,也就是说要插入到脚本的第7行。
在脚本的第7行前插入一行空白行,然后输入:
web_reg_save_param("UserSession",
这个“UserSession”就是到时要使用的参数名称,建议取一个有意义的名字。
到目前为止,整个web_reg_save_param函数还没完成。
(4)确定web_reg_save_param中的边界。
web_reg_save_param函数主要是通过动态数据前后的固定字符串,来辨识要撷取的动态数据的,所以还需要找出动态数据的边界字符串。
1)确定左边界字符串
再回到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=",
2)确定右边界字符串
接下来要找出动态数据的右边界字符串,这个字符串就比较好找了,从动态数据的最后一个字符开始,通常就是要找的右边界字符串。
以这个例子来看,就是“>”,所以再把右边界字符串加入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,
至此,已经完成了一个关联了,接下来就是执行脚本,验证其是否能成功运行。假如还是有问题,就要检查看看是否还需要再做另一个关联。
4.将脚本中有用到关联的数据,以参数取代。
利用前面所介绍的方法找到需要关联的地方,把需要变更的常量用参数进行取代,具体参数化步骤参看第3章3.2.1节的内容,在此不再赘述。
参数化的过程执行如下操作:
(1)用参数替换脚本中的常量。
(2)为参数设置属性和数据源。
参数化的过程要注意以下事项:
(1)在参数化的过程中,只有函数中的参数能被参数化,而且也不是所有函数中的参数都能参数化。例如,Lrd_stmt只能参数化mpcText。
(2)参数化CORBA或General_java Vsuer这两个地方保证完整性,必须参数化整个字符串。
(3)参数的格式要与所录制的脚本相一致,否则脚本可能不能正常运行。
3.3.4 关联中的常见问题
设置语句关联时,如果经验不足,经常会出现一些问题。本节将提供一些关联过程中常见的问题的解决方法,其他出现的问题需要在实际应用中具体分析和处理。
1.在脚本的data目录下找不到录制时的快照(snapshot)。
问题可能的原因如下:
(1)脚本是由VuGen
6.02或更早的版本所录制的;
(2)汇入的Action不会包含快照(snapshot)的档案;
(3)脚本存储在只读的目录下,造成VuGen无法存储执行时撷取的快照;
(4)某些步骤并不会产生快照,如浏览某个资源;
(5)快照功能被取消。
解决办法:选择“Tools”>“General options”>“Correlation”>“Save correlation information
during replay”,开启快照(snapshot)功能。
2.开启WinDiff时出现“File no longer available”的错误信息。
问题的原因如下:WinDiff工具有限制,对于包含空格符的目录或是脚本无法开启。
解决办法:为目录或脚本命名时不要使用空格符,并且尽可能将名称取短一点。
3.录制时突然跳出“Correlation warning”对话窗口。
问题的原因如下:
如果勾选自动关联的“Issue a popup message and let me decide online”选项,当VuGen发现有可能要做关联的数据时,就会跳出“Correlation
warning”的窗口,询问要做“关联”(Correlation in script)还是要“忽略”(Ignore),如图3-26所示。
图3-26 关联警告
解决方法:可以勾选“Perform correlation in script”,让VuGen自动作关联,不会再跳出询问窗口;或者勾选“Disable correlation engine”,关闭自动关联的功能。
4.如何打印出参数值
解决方法:利用lr_eval_string与lr_output_message这两个函数来打印出参数值。
例子:
lr_output_message("Value Captured=%s",lr_eval_string("{ParameterName}"));
5.如何手动启动“Scan action for
correlation”的功能
解决方法:要启用“Scan Action for Correlation”功能,请单击“Tools”>“General options”>“Correlation tab”,勾选“Show Scan for correlation
popup after replay of Vuser”选项。