+ 首页>>技能>>内容

技能[PLAYING QTP] PART 06 – OBJECT REPOSITORY301次围观

[PLAYING QTP] PART 06 - OBJECT REPOSITORY

PART – 06 – OBJECT REPOSITORY
在说对象库之前,现在说一下QTP对控件识别的工作原理。

控件识别的工作原理:

打开Tools->Object Identification,我们可以清楚的看到,QTP对对象的识别,有4种模式:
[PLAYING QTP] PART 06 - OBJECT REPOSITORY

(1) Mandatory Properties 强制属性识别

可以一个或多个属性的组合,如果根据此级别识别了对象,则退出识别流程。
如果根据对象库的属性值与运行时不匹配,则报错(无法找到对象)。
如果属性在当前Application中有多个对象匹配,则使用辅助属性识别模式。

(2) Assistive Properties 辅助属性识别

辅助属性识别是对强制属性识别的一个补充,当强制属性识别识别时匹配多个对象,就根据辅助属性识别设置的属性及属性值来进行识别。

注:强制属性在实际的匹配中,只要有一项不一致就报错,而辅助属性则没有这个要求。

(3) Smart Identification 智能识别

智能识别属性可以分为Base Filter Properties(基本过滤属性)和Optional Filter Properties(可选过滤属性),它们的关系就像强制属性和辅助属性。
智能识别机制主要工作于测试脚本运行时(对象允许智能识别为真),当对象库中对象的强制属性(或辅助属性)与被测应用程序中对应对象的属性不一致时,智能识别机制将会启动。

脚本方式设置智能识别:
如果是要在脚本执行过程中禁用所有的智能识别,那只需要在开头加上

Dim App 
Set App = CreateObject("QuickTest.Application")
App.Test.Settings.Run.DisableSmartIdentification = True

如果只是要禁用部分对象的智能识别,比如禁用WebEdit的智能识别,则用

Dim App 
Set App = CreateObject("QuickTest.Application")
App.Options.ObjectIdentification("webedit").EnableSmartIdentification = False

手动方式设置智能识别:
禁用所有的智能识别:
File –> Setting –> Run ,把“Disable Smart Identification during the run session”前面的复选框选上,则不支持智能识别,反之支持。
修改智能识别设置:
Tools –> Object Identification,可以通过设置“Enable Smart Identification”和“Configure”来改变智能识别设置。
注:有是有智能识别能帮你更好地识别到对象,但是,有时候也会帮倒忙,比如你想点的按钮没有识别到,却智能识别到了别的按钮上进行了操作,比如有个控件在对象库中记录的属性已经过期,但是智能识别虽然能识别到,但是却严重影响了脚本的执行效率,还不如报下错,update一下对象属性来的快。

(4) Ordinal Identifier 顺序标识符
QTP除了可以获取到被测对象的强制属性、辅助属性值外,还可以获取到被测对象的Ordinal Identifier值。当QTP发现有多个对象具有相同的主属性值、辅助属性值而无法对它们进行唯一识别时, Ordinal Identifier 会获取每个对象的序列值,以将它们区别开来。
由于序列值是一个相对值,任何页面的变更都有可能导致这些值发生改变,因此,只在主属性与辅助属性无法唯一识别对象的情况下,QTP才会获取该序列值。
在运行测试脚本时,如果使用对象的属性值以及Smart Identification机制都无法唯一识别应用程序中的对象,才会使用到序列值。如果QTP可以通过其它属性值对对象进行识别,则会忽略序列值。QTP可以使用以下类型的ordinal identifiers来识别对象:

  • Index 表示对象在程序代码中的出现顺序,这个顺序是相对于其它具有相同属性的对象而言的。
  • Location 表示对象在窗口、Frame或对话框中出现的顺序,这个顺序是相对于其它具有相同属性的对象而言的。
  • CreationTime(仅适用于Browser对象) 表示Browser对象打开的顺序,这相顺序是相对于其它已打开的具有相同属性的对象而言的。

在对控件的识别中,主要识别流程为:

1. 先对这个控件指定的几个强制属性进行比较,若找不到,则报“找不到对象”,结束对象识别;若只找到一个对象,则继续下面的操作,结束对象识别;若找到的对象多于一个,到下一步进行辅助属性的识别。
2. 辅助属性的识别过程中,如果能确定到一个控件,则结束识别,如果还是不能确定到一个控件,则到下一步进行智能识别。
3. 智能识别中 继续添加属性筛选, 若添加的对象属性造成无对象匹配,则淘汰该属性。
4.若所有属性的添加或淘汰都无法识别唯一对象,QTP将应用ordinal identifier去识别对象。

Object Repository 对象库:

QTP对象库简称OR,也就是Object Repository,是一个存放 QTP封装对象的地方,自从mercury引入了关键字驱动测试之后,对象库就一直起着举足轻重的作用。
QTP对象库的优势:

  • 对象与脚本的完美分离,降低巨大的维护成本。
  • 更好的定位对象识别问题,提高对象识别排错的效率。
  • 可轻易的修改对象库中对象的描述属性,并能够更好的管理对象。

在QTP中可以直接通过CTRL+R打开QTP对象库,并可在其中进行添加对象、删除对象、复制对象等操作。
并且可以实现某个对象的属性增删改操作。这一点功能是非常实用的,以后可以结合spy和对象高亮进行快速排错。
[PLAYING QTP] PART 06 - OBJECT REPOSITORY
上图中,左侧是对象库中所保存的对象的一个树形结构,点击树形结构中的对象,右侧会显示出该对象所以对应的各种信息。
还记得上一节说到的RO和TO吗?这里右侧显示的属性,就是TO。

对象库的两种导出:

先用 Resources->Object Repository 或 Ctrl+R 的方法打开对象库。
然后就有了下面两种导出:

  • File->Export Local Objects
  • File->Export and Replace Local Objects

①和②都有导出对象库的功能,但②比①多一个替换功能。
例:添加一个对象至对象库
使用①导出对象库后,对象库中对象无变化,还是本地对象。
Resource->Associate Repositories中的Repositories中无副对象库文件加载。
使用②导出对象库后,对象库中原对象全部都由本地对象变为副对象。
Resource ->Associate Repositories中的Repositories中有了一个副对象库文件,为刚刚导出的对象库文件。

对象库的合并:

打开Resources->Object Repository Manager。
然后在Tools菜单下,点击 Object Repository merge tool。

[PLAYING QTP] PART 06 - OBJECT REPOSITORY
选择2个要进行合并的对象库文件,进行合并。
一次只能合并2个,如果有多个对象库需要合并,则两个两个分别合并。
如果在合并的过程中,出现有冲突的对象,它会自动高亮出来,然后可以做相应的处理。

对象库的导入:

打开 Resources->Associate Repository,
点【+】选择共享对象库的.tsr文件,
点击对应的对象库Action从 Available Actions 加到 Associate Reposity 中即可。
[PLAYING QTP] PART 06 - OBJECT REPOSITORY

动态添加对象库的tsr文件:

直接举例说明:
录制一个百度页面的操作,然后将对象库导出,保存成一个obj.tsr文件。
然后使用如下代码进行动态添加tsr对象库。

Call AddObjectRepository("obj.tsr")
Browser("百度一下,你就知道").Page("百度一下,你就知道").WebEdit("wd").Set "123123123"
 
Public Function AddObjectRepository(objectrepositoryname)
    Dim Pos
    '检查参数是否有后缀名,没有则增加后缀
    If instr(1,objectrepositoryname,".tsr")>0Then
        RepPath = objectrepositoryname
    Else
        RepPath = objectrepositoryname & ".tsr"
    End If
    msgbox RepPath
 
    RepositoriesCollection.RemoveAll()
    RepositoriesCollection.Add(RepPath)
    Pos = RepositoriesCollection.Find(RepPath)
 
    If Pos <> 1 Then
        msgbox "用例对象库导入失败!"
    End If
End Function

动态添加对象到对象库:

hp官方并没有为QTP提供一种方式可以在脚本运行时动态的添加对象到对象库中 。
这里引用 IQuickTest 提供的一种方法,通过脚本的方式创建一个新的测试对象, 并为其设置属性,最后添加到对象库中。
脚本为:

' 创建ORAOM对象
Set oraom = CreateObject("Mercury.ObjectRepositoryUtil")

' 载入指定的对象库文件
oraom.Load "C:\iquicktest.tsr"

'为notepad创建一个新的Window类测试对象并为其设置属性
Set WinObj = CreateObject("Mercury.StdWindow")
WinObj.SetTOProperty "is owned window", False
WinObj.SetTOProperty "is child window", False
WinObj.SetTOProperty "regexpwndtitle", "Notepad"
WinObj.SetTOProperty "regexpwndclass", "Notepad"
WinObj.SetTOProperty "text", "Untitled - Notepad"

' 把notepad窗口对象添加到对象库中
oraom.AddObject WinObj, Null, "Notepad"

' 创建一个notepad下的WinEditor对象,并为其设置属性
Set EditObj = CreateObject("Mercury.WinEditor")
EditObj.SetTOProperty "nativeclass", "Edit"

' 将Editor对象添加到notepad窗口对象中
oraom.AddObject EditObj, WinObj, "Edit"

' 保存对象库文件
oraom.Save

' 释放对象引用
Set WinObj = Nothing
Set EditObj = Nothing
Set oraom = Nothing
MsgBox "对象库更新完毕"

说明:其中Mercury.StdWindow为window类型的progID
所有的ProgID都存储在
HKEY_LOCAL_MACHINE\SOFTWARE\Mercury Interactive\ QuickTest Professional\MicTest\Test Objects中。
这种方法我并没有在实战中使用过,不过可以作为学习的参考,拓展一下思路。
脚本中用到的几个点都很厉害,值得学习一下。

OP与DP的对决:

  • OP: ObjectRepository Programming 对象库编程
  • DP: Description Programming 描述性编程

上面说了半天,都是在说对象库,既然说到了对象库,就不得不说一下对象库编程和描述性编程。

对象库编程:

顾名思义就是使用对象库中记录的对象进行编程,这种编程方式离不开对象库,经常有童鞋来问,为什么录制的脚本复制到别的电脑上就无法使用了,很大的原因就是因为你只是复制了脚本,而对象库并没有复制过来,导致脚本报错。

对象库编程的脚本如:

Dialog("Login").WinButton("OK").Click

描述性编程:
就是在脚本中,加入对对象的属性的描述,如:

Dialog("Login").WinButton("text:=OK").Click

它和对象库编程最大的区别就是吧需要识别的对象的属性,从对象库中转移到了脚本。通过在脚本里面的特殊语法格式,来告诉QTP识别对象的方法。
关于如何进行进行描述性编程,这里只是简单的说了一下,每本关于QTP的书上都会有详细的讲解,如果对描述性编程不了解想深入学习的童鞋,请看书学习。
OK,先从客观的角度分析一下两者的优势:
对象库的优势:

  • 可以通过Complete Word、“F7”等多个方式进行高效编程。描述性编程不行。
  • 修改对象库中某对象名称,能自动批量把脚本中该对象的名称都修改好,不用自己一个个去找。描述性编程不行。
  • 出错较少,如果写描述性编程的过程中,属性多个空格少个空格什么的,很常见,而且定位要花很多时间时间。
  • 对象查看起来比较清晰,而且脚本简洁,提高了阅读脚本的效率。
  • 能批量添加对象至对象库,也能批量删除。
  • 写脚本的时候可拖拉对象生成脚本。
  • 更新对象比较方便,对象库中选中需要更新的对象后,Update一下就搞定了。

描述性编程的优势:

  • 脱离对象库,脚本在无对象库的情况下,可直接运行。
  • 脚本编写很灵活。
  • 能完成一些特殊的情况。
  • 常用于框架,能降低与其他Action之间的耦合,减少脚本与脚本之间的相互影响。

为什么这两个会有使用上的争议,我的猜想是如下几点:

  • 有些人觉得使用对象库很麻烦,维护对象库也很麻烦,在复制脚本的时候,如果是对象库编程还需要导出对象库数据才行。所以觉得直接复制脚本就能使用的描述性编程很好用。
  • 有些人认为由于“描述性编程”带上“编程”两个字,瞬间感觉如果纯写描述性编程,那就是“高端大气上档次”。
  • 由于描述性编程在维护的时候,难度明显大于对象库编程,所以选择了尽量使用描述性编程进行脚本的编写(你懂的)。

我个人认为,结合使用效率更好一些,关键还是看场景。

场景一:

百度搜索cystest,然后点击搜索。
像这类的线性动作,而且输入搜索关键字的文本框和百度一下按钮几乎是不会变动的,那很显然使用对象库编程要方便的多。
[PLAYING QTP] PART 06 - OBJECT REPOSITORY

SystemUtil.Run"iexplore.exe","http://www.baidu.com"
Browser("Browser").Sync
Browser("Browser").Page("百度").WebEdit("关键字").Set "cydtest"
Browser("Browser").Page("百度").WebButton("百度一下").Click
Browser("Browser").Sync
Browser("Browser").Close

场景二:
选择日期
[PLAYING QTP] PART 06 - OBJECT REPOSITORY
上面这种控件,我想是再常见不过的了。这里的场景就比较适合实用描述性编程了,为什么呢?因为很显然日期控件里的日期是可变的,每个月显示的位置都会有所差异,而且就算只用这一个月,难道需要1号到31号这31天的对象,全都加到对象库中么?很显然,这不是个巧办法。所以这里就需要用到描述性编程。
对象库中记录至输入框。
[PLAYING QTP] PART 06 - OBJECT REPOSITORY
脚本为:

Dim Dim X
X = "8"
Dim objWidth 
objWidth = Browser("Browser").Page("Page").Frame("Frame").WebEdit("WebEdit").GetROProperty("width")
With Browser("Browser").Page("Page").Frame("Frame")
    .WebEdit("WebEdit").Click  objWidth  -10 , 5
    .WebElement("class:= urCalPicDay urBorderBox","innertext:=" & X,"index:=0").Click
End With

这里说明一下:
1. X是参数化用的,名字随便起的。
2. 为什么用要用到objWidth,那是因为识别问题,我这边的这个控件被识别成了WebEdit,且最后的那个点出日历表的小图标无法点击到,所以用了Click的坐标参数。
3. 由于日历上会有本月的1号和下个月的1号,本月的30号和上月的30号,为了定位到我想要的日期,所以描述的时候使用了class属性。
4. 这么写是举例之用,在这样有很多相同类型的控件,且不可能一一添加对对象库时,会如此使用。

具体的场景,大家可以在日常工作中多做总结,上述日期的点选方法只是个举例,重点在写描述性编程,日期选择支持手动写入的话,如下一句就搞定了。

Browser("Browser").Page("Page").Frame("Frame").WebEdit("WebEdit").Set "2014-1-9"

场景三:
勾选上页面上所有的复选框
有时候会需要填写表单,而表单上有大量的复选框,一个个添加到对象库中比较繁琐,而且如果每个角色的选择项又会有所差异,那显然对象库编程要简便一些:

Dim oWebChkDesc
Set oWebChkDesc = Description.Create
'属性描述
oWebChkDesc("micclass").value = "WebCheckBox"
oWebChkDesc("html tag").Value = "INPUT"

' 获取所有匹配描述的对象
Dim allObjects
Set  allObjects = Browser("xxxxx").Page("xxxxx").ChildObjects(oWebChkDesc)
'历遍所有对象
For i = 0 to  allObjects .Count - 1
    ' 勾选操作
    allObjects(i) .Set "ON" 
Next

目前先举三个例子,对象库编程和描述性编程各有利弊,各有能发挥各自长处的地方,合理的结合使用,才能达到更好的效果。

正则表达式的使用:

对象库编程
对象库编程过程中,遇到有些对象需要使用正则表达式来描述对象,比如使用不用的账号登录后,标题里会有登录者的名字等。
这里举个简单的小例子,比如被测系统页面上有个控件是“当前任务”,点击这个链接能进入当前任务的列表,但是在当前任务的四个字后面,会有一个括号,而括号里会显示出任务数,由于每次任务数的不同,导致对象在添加到对象库后,时常无法正常识别,这时候,可以使用正则表达式来解决。
打开对象库->找到需要使用正则的对象 -> 点击[#]按钮 -> 描述->确定->搞定。
[PLAYING QTP] PART 06 - OBJECT REPOSITORY

描述性编程
描述性编程的话,就可以直接在脚本中进行描述。

Browser("CreationTime:=0").Page(":=").WebElement("innertext:=当前任务\(.*\)").Click

QTP支持的正则常用表达式

  • 使用反斜杠字符 ( \ )
  • 匹配任意单个字符 ( . )
  • 匹配列表中的任意单个字符 ( [xy] )
  • 匹配不在列表中的任意单个字符 ( [^xy] )
  • 匹配某个范围内的任意单个字符 ( [x-y] )
  • 特定字符的零次或多次匹配 ( * )
  • 特定字符的一次或多次匹配 ( + )
  • 特定字符的零次或一次匹配 ( )
  • 对正则表达式进行分组 ( ( ) )
  • 匹配几个正则表达式中的一个表达式 ( | )
  • 在一行的开始进行匹配 ( ^ )
  • 在一行的结尾进行匹配 ( $ )
  • 匹配包括下划线在内的任一字母数字字符 ( \w )
  • 匹配任意非字母数字字符 ( \W )

最后来回顾一下说的几点吧:

[PLAYING QTP] PART 06 - OBJECT REPOSITORY

写了这么多,难免会有疏漏。大家可以留言补充。
PART – 06 END
转载请注明出处与原作者。
如果你觉得文章对你有所帮助,请留言。
如果你想请作者喝杯咖啡,请点这个超链接

+ 猜你喜欢...

===== 关于 DiggerPlus =====
DiggerPlus是国内新锐测试人垂直内容博客,专注于挖掘测试工具,普及测试技术,专注于测试人能力提升,博客上线后就受到广大测试人的热烈追捧;此外,DiggerPlus深度整合评测资源,揭秘科技数据和真相,让读者更懂科技,更好地把玩科技。 我们始终保持"独立,客观,严谨,优秀"的优良作风,努力为读者带来源源不断的优质内容。想访问更多酷毙的测试人网站?赶紧来DiggerPlus测试人网址导航看看吧!

===== DiggerPlus Team =====
DiggerPlus Team是DiggerPlus官方发起的团队,这是一群热爱科技,热爱测试,喜欢深度挖掘的热血测试人,他们是评测师,测试专家。 我们欢迎优秀的测试人加入DiggerPlus Team。 加入DiggerPlus,可以成为我们的认证Dper,认证Dper拥有DiggerPlus独一无二的专栏并得到个人展示。

===== DiggerPlus 官方读者群 =====
DiggerPlus官方读者群(一)

+ 关于本文作者

不随波逐流,做不平凡的测试人。

的专栏 | 专栏作者 | 访问Dylan_陈永达的主页

+ 发表评论

开源中国精彩推送

基于开源中国OpenAPI开发
  • Copyright © 2014 DiggerPlus. 43 queries in 0.490 seconds.
    使用合作网站账号快速登录,更多精彩等着您: 开源中国