2

第二部分 对象库和对象属性

1.       对象识别和智能标识

对象的属性识别主要来自QTP识别的网页(或者其它)本身的控件设计,因此对象的属性是灵活多变的,有时候我们需要添加一个或多个属性,有时需要删除一个或多个属性,具体的情形要根据当时的情况而定。录制或编写测试脚本的时候要注意多观察:哪些属性能够唯一表示一个对象,哪些属性值是随机变化的,哪些属性需要多次运行时都能够匹配。

¨        对于对象属性是变化的,可以参数化/或者用正则表达式(参见第一部分基础知识),即在选定的对象的属性值里面采用正则表达式(具体书写规则参见“正则表达式”一节)或者使用参数表(不是很灵活)来对其进行赋值。这样QTP运行时会自动查找对象进行匹配,比较方便,不需要反复添加对象。

¨        


报匹配多个对象错误,可以spy(如下图)查看对象,添加一个该对象另一个唯一标识属性,而这些能够唯一标识的属性需要自己仔细观察来寻找,通常这些唯一标识对象的属性往往是可变化的,如果需要获取对象属性值,这种方法事实上并不是很明智。例如Web复选框类WebCheckBox的的对象属性基本上都是一样的,录制时的区别可能只是自动在他的运行时属性里添加index或location使录制的对象变为_2、_3等等,否则运行时就会提醒无法唯一表示对象,而QTP本身的智能表示机制就可以解决这个问题,不需要手工添加属性来区别。


 


 

 

 

 

¨        上图中显示能够为一区别于其它几行的对象是凭证号对应的列,其对象属性值1117是不同与其它对象的唯一标识,然而在对象捕捉的时候如果将此对象属性值也包含在内的话,下次运行时如果第一行1117号票据已经不存在的话,QTP就会报“找不到对象”错误。所以对于多个完全相同的对象,可以采用添加index,location,createtime等特殊属性的“定位法”来识别对象。例如:

index: 按照程序源码,绘制对象的先后标识对象,所以与其它相同对象是相互依赖,当其它对象发生变化后,原先的所有对象index属性要发生变化,开始是0。东亚银行前端交易页面某些交易(例如RB7H,RB1904等)进行时需要获取webelement的变化的属性值“innertext”,为了能够将交易进行下去,只能使用方法三里的方法:删除属性  “innertext”,然后通过调整index的值来定位所需要获取的属性的属性值所在的位置。

location:根据对象的位置进行确定,从上到下,从左到右

CreateTime:按照对象被浏览器打开的先后标识对象)

在对象库里添加一个自动含有index标识属性的对象,然后每次通过SetToproperty来改变index值,对对象进行数据驱动,使其操作另一个对象,但脚本始终操作原先index属性值的对象;这时考虑把该对象删除掉,重新添加一个不自动含有index标识属性的该类对象,然后,手工添加index标识属性,后来脚本能正常 工作了,可见两次的对象属性完全一致,但形成方式不一样,导致的结果往往也不一样。

¨        而QTP自身为了解决相似问题在windows控件里都会添加window id这个属性,它是个随机变化的属性,每次都会随机产生一个与上次不同的值,所以这样反而无法在下一次运行时对对象进行匹配,总是提示找不到对象,有时可以删除对象的变化的属性来解决识别问题,再进行录制脚本的时候可以事先在工具\对象标识(如图)里面通过配置各个


类的属性操作来删除这些可变属性,重新进行录制或添加对象就可以了。

选择相应的插件类型(如Web、Activex等),然后对相应的类(如WebElement)分别在强制属性和辅助属性里点击“添加/删除”按钮,配置你所需要的能够为一标示你所需要的对象的属性。


如需启用智能标识,则选中“启用智能表识”,然后点击“配置”按钮(如图):

    同样在“基本筛选属性”和“可筛选属性”里面通过点击“添加/删除”按钮来选择进行对象智能标识的属性。

¨        另外换一种思维方式,采取等效的方法;比如用键盘代替鼠标或用操作系统本身特性去解决问题。这种方法可忽略对象库中的对象,不需要识别,前提是除去判断语句;但是这种写法——使用键盘模拟函数只能够处理弹出对话框或msgbox中只有一个按钮的情况,或者两种但是默认停留在需要点击的地方。

相关信息参见下文“键盘模拟”。

2.       万能键盘模拟函数

Extern.Declare micVoid, "keybd_event", "user32.dll", "keybd_event", micByte,micByte,micDWord,micULong

Extern.keybd_event 32(参数),0,0,0


由于space键代码为32,所以上述代码模拟了点击space键操作,其它键盘操作代替可由下表查得:

更多的键盘代码请参见:虚拟键盘码一览表

3.       键盘模拟函数:WScript.Shell的应用

set WshShell=CreateObject("WScript.Shell")
WshShell.SendKeys "{ENTER}"     '模拟键盘进行操作
键盘键-函数一览表

Key

Argument

BACKSPACE

{BACKSPACE}, {BS}, or {BKSP}

BREAK

{BREAK}

CAPS LOCK

{CAPSLOCK}

DEL or DELETE

{DELETE} or {DEL}

DOWN ARROW

{DOWN}

END

{END}

ENTER

{ENTER} or ~

ESC

{ESC}

HELP

{HELP}

HOME

{HOME}

INS or INSERT

{INSERT} or {INS}

LEFT ARROW

{LEFT}

NUM LOCK

{NUMLOCK}

PAGE DOWN

{PGDN}

PAGE UP

{PGUP}

PRINT SCREEN

{PRTSC}

RIGHT ARROW

{RIGHT}

SCROLL LOCK

{SCROLLLOCK}

TAB

{TAB}

UP ARROW

{UP}

F1

{F1}

F2

{F2}

F3

{F3}

F4

{F4}

F5

{F5}

F6

{F6}

F7

{F7}

F8

{F8}

F9

{F9}

F10

{F10}

F11

{F11}

F12

{F12}

4.       等待时间的艺术

某个对象是否出现不明确或者应用系统响应时间不确定的时候,我们往往采取Wait的方法,而且这个时间是不确定,所以一般初学者会考虑使用最大时间值(系统最慢的情形)。其实完全没有必要等这么长时间,而且如果系统忽快忽慢怎么办?总不能每次“跑脚本”之前都去修改一次吧,这样脚本少还可以,脚本多(一个或多个测试集往往牵涉到几十上百个测试脚本)了呢?这样的话,脚本维护的代价太昂贵了!

这种情况下可以考虑写一些循环语句代替wait语句,这些语句写得合理的话,会在系统响应的第一时间做下一步操作,而长时间无响应就可以通过跳出条件来终止运行,报告系统连接超时就可以了。因为这种速度的系统版本客户是不会要的,一般情况下这种测试是没有意义的。

下面是我曾经使用的一些例子:

¨        系统必须作出响应的情形,无须跳出,只待系统正常,否则手动干预:

Do                                                                   

  If  Browser("teller").Page("teller").Frame("content").WebList("ACCT_STATUS").

     GetROProperty("value")  = "" Then                                  

  Else                                                               

  Exit Do                                                            

  End If                                                              

Loop                                                                

¨        使用WaitProperty函数,该函数的作用基本上和If……Exist(second)……End If比较类似。但是它的判断结果有True和False两种,在If的判断语句的时候很方便,因为条件成立可以执行下一步,反之如果需要不成立而去执行下一步,他的作用就不是If……Exist(second)……End If所能比的了。

WaitProperty("visible",true,10000)

第一个引号内参数是对象的属性名称,第二个是该属性的值,第三个就是等待的时间,单位是毫秒,具体的应用如:

If Browser("teller").Page("teller").WebElement("手续费打印完毕!               

  ").WaitProperty("innertext""手续费打印完毕!"60000) = False Then        

  Browser("teller").Page("teller").Image("ToolBar_Refresh_0").Click             

Elseif Browser("teller").Dialog("MicrosoftInternet Explorer").Exist(10)Then        

    Browser("teller").Dialog("Microsoft InternetExplorer").WinButton("确定").Click

       Browser("teller").Page("teller").Image("ToolBar_Refresh_0").Click           

       Reporter.ReportEvent micFail "发出托收票据" "交易失败"             

       ExitAction(1)                                                       

End If                                                                 

¨        定义弹出框存在性状态,使用循环语句判断

Dim blnDone,counter

blnDone=false

counter=1

While blnDone

       Wait (1)

      blnDone=Window("iexplore").WinObject("OK").Exist

       counter=counter+1

       If counter=10 then

          blnDone=True

       End if

Wend

¨        循环判断,跳出条件是i=10

Dim i

i=1

while((window("iexplore").WinObject("OK").Exist) and (i<10))

      window("Iexplore").WinObject("OK").Click

i=i+1

wend

5.       验证弹出错误类型

   If Browser("teller").Dialog("Explorer").exist(1)then

em=browser("teller").dialog("Explorer ").static("密码错误!").getRoproperty("text")
    If em<>(datatable.value("error_info"))then
           msgbox(em)

reporter.ReportEventmicFail,"系统登陆","密码错误"
        End If
        Browser("teller").Dialog("Explorer").close

‘或者Browser("teller").Dialog("Explorer").WinButton(确定).Click
      End if

一:对于Dialog中,虽然提示信息对象名称是"用户密码错误",但如果信息对象名称是“该用户不存在”,不用更改会自动识别,我想主要是录制第一遍时,“用户密码错误”只是让运行时能找到这个控制,而不管它是什么内容,因为在对象仓库中,text不是决定该对象的属性。事实上,可以经过对象属性配置,在Static对象的强制属性中添加text属性,然后上面的语句就可以这样写了:

IfBrowser("teller").Dialog("Explorer"). static("密码错误!").exist(1) then

msgbox(密码错误!)

Reporter.ReportEventmicFail,"系统登陆","密码错误"

Else

Reporter.ReportEventmicPass,"系统登陆","登陆成功"

Browser("teller").Dialog("Explorer").close

‘或者Browser("teller").Dialog("Explorer").WinButton(确定).Click
     End if

    这种情况要求需求必须明确,要知道这种情况下的弹出框内容,否则就是无的放矢了。

二:如果对于提示信息比较长的,可以用mid(error_message,n,m)取一部份特征提示信息进行验证,这样我想可以节省处理时间,又可以避免长度以及空格等字符的处理。

6.       虚拟对象

在实际测试过程中,很多时候网页上的控件并不能都被QTP识别,例如网页上一个flash动画,实际上是一个链接,但是QTP无法识别出flash这个控件,这时使用QTP中的虚拟对象来解决这个问题。

下文以WebButton为例:

1.        使用虚拟对象,将WebButton设为一个对象,点击工具——虚拟对象——新建虚拟对象,弹出如下对话框:

 

2.        点击“下一步”,进入下一个对话框:

 

3.        在类里选择你想将WebButton设为那个QTP能够识别的对象,点击“下一步”:

4.        打开你的页面,页面中包含你要的虚拟的对象,并且点击上面对话框中的标记对象按钮,页面会最小化,鼠标会编程”+”,你可以使用”+”来限定虚拟对象的范围选好后,会在宽度和高度中显示虚拟对象的高和宽,并且点击next,弹出如下对话框:

5.        选择整个父层次或者仅父类,弹出如下对话框:

6.        设定虚拟对象的名称,以及收藏的名字,点击完成,虚拟对象添加完成。然后点击工具——虚拟对象——虚拟对象管理器可以查看编辑虚拟对象:

7.        最后是编写相关的语句,进行预期的操作,下面一句是一个简单的例子,这里Vocollection2是虚拟对象父类名,虚拟对象名为button;虚拟对象使用的具体语法可以参见QTP的帮助文档:

Browser("Browser").Page("Page").WebButton("关闭窗口").Activex("Vocollection2").VirtualButton("button").Click

7.       获取对象属性名称用法:

GetRoProperty——从应用程序界面上获取对象属性(即,是脚本运行时,获取的对象动态属性值),例如:获取对象库中index属性值,似乎只能用GetToProperty,因为应用程序界面上对象没有该属性,只是QTP为识别该对象创立的描述属性;

GetToproperty——从对象库中描述对象的属性,静态值
GetToProperties——获取用于标识对象的属性集;对于这个集合,有count等属性。

关键在于RO和TO,R,就是Runtime,T就是Testtime,O就是Object。因此顾名思义,RO就是在测试执行时的对象,TO就是录制/编写测试时的对象。是同一个类在不同的时间生成的不同的实例,一般来说TO是静态的,而RO是动态的(每次执行测试都会生成新的实例)。

8.       ChildObjects的应用

ChildObjects可以返回界面上满足条件的对象集合,而且与对象库里是否有这些对象无关,这就可以简化对象库;返回的对象集合的count方法可以返回对象个数,这就可以通过下标对单个对象进行操作;在出现index标识对象时可以进行运用如:

Set m_WinCheck=Description.Create()                                                                    
      m_WinCheck("type").Value="checkbox"                                                              
      set All_WinCheck=Browser("teller").Page("teller").Frame("content").ViewLink("dbtable").ChildObjects(m_WinCheck)
      n=All_WinCheck.Count()                                                                           
      for i=0 to n-1                                                                                        
        All_WinCheck(i).Set"ON"                                                                           
      next                                                                                                


这种方法操作对象的好处是不需要在对象库里添加大量的重复的对象,具体的用法是如下图界面中,通过使用对象探测器观察这些对象的共有属性,例如type、html tag、name等等,通过这些共性来确定你所需要捕捉对象的群体,以上这段代码等价与下面这些语句:

Browser("teller").Page("teller").Frame("content").ViewLink("dbtable").WebCheckBox("sys_dao_check_null").Set"ON"       Browser("teller").Page("teller").Frame("content").ViewLink("dbtable").WebCheckBox("sys_dao_check_null_2").Set"ON"     Browser("teller").Page("teller").Frame("content").ViewLink("dbtable").WebCheckBox("sys_dao_check_null_3").Set"ON"     Browser("teller").Page("teller").Frame("content").ViewLink("dbtable").WebCheckBox("sys_dao_check_null_4").Set"ON"     Browser("teller").Page("teller").Frame("content").ViewLink("dbtable").WebCheckBox("sys_dao_check_null_5").Set"ON"     Browser("teller").Page("teller").Frame("content").ViewLink("dbtable").WebCheckBox("sys_dao_check_null_6").Set"ON"     Browser("teller").Page("teller").Frame("content").ViewLink("dbtable").WebCheckBox("sys_dao_check_null_7").Set"ON"     Browser("teller").Page("teller").Frame("content").ViewLink("dbtable").WebCheckBox("sys_dao_check_null_8").Set"ON"    

这就需要捕捉8个对象到对象库里,但是用前文ChildObjects的方法,就只需要一个对象,甚至有些时候不需要添加对象。皆如上图则罢,但是很多时候,远远不止这么几行信息,所以使用适当的方法能够很大幅度的提高工作效率,相当于全选。

9.       SetProperty函数的应用

如上例图示,这八行语句也可以使用SetProperty函数含实现单一对象的多次操作。具体方法可以参见如下代码:

Dim n                                                                                  

n = 0                                                                                   

Do while n <8                                                                           

Browser("teller").Page("teller").Frame("content").ViewLink("dbtable").WebCheckBox("sys_dao_check_null").SetTOProperty "index" , n                                                                

Browser("teller").Page("teller").Frame("content").ViewLink("dbtable").WebCheckBox("sys_dao_check_null").Set "ON"                                                                              

n = n + 1                                                                                

Loop                                                                                   

这种方法的缺点是必须知道页面参数表里一共有多少行参数,给该循环一个跳出的条件。或者也可以用Count函数来进行全选,作用就和ChildObjects函数一样了。     

10.    wintreeview一些操作

选择一个条目:wintreeview.select(item)'根是0
根的名称:wintreeview.getitem(0)

11.    "is+*"类型function

isarray'是否是数组
isconnected'判断QTP是否连接到TD
isdate'是否是合法的日期类型
isempty'判断是否初始化
isNull'判断是否为空值
isNumeric'判断是否是数字型
isobject'判断是否一个功能对象
isready'判断设备是否准备就绪
isRootFolder'是否是根目录

12.    FireEvent的使用

可以对一个对象进行更复杂的操作

如:FireEvent("onfocus")  '使一个控件获取焦点
     FireEvent("ondblclick")  '实现双击/也可以在事件设定中针对该对象事件响应。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值