[PLAYING QTP] PART 06 – OBJECT REPOSITORY

part06

PART – 06
OBJECT REPOSITORY

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


控件识别的工作原理:

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

part06_01

(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和对象高亮进行快速排错。

part06_02

上图中,左侧是对象库中所保存的对象的一个树形结构,点击树形结构中的对象,右侧会显示出该对象所以对应的各种信息。

还记得上一节说到的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。

part06_03

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


对象库的导入:

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

part06_04


动态添加对象库的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,然后点击搜索。

像这类的线性动作,而且输入搜索关键字的文本框和百度一下按钮几乎是不会变动的,那很显然使用对象库编程要方便的多。

part06_05

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

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

对象库中记录至输入框。

part06_07

脚本为:

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

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


正则表达式的使用:

对象库编程

对象库编程过程中,遇到有些对象需要使用正则表达式来描述对象,比如使用不用的账号登录后,标题里会有登录者的名字等。

这里举个简单的小例子,比如被测系统页面上有个控件是“当前任务”,点击这个链接能进入当前任务的列表,但是在当前任务的四个字后面,会有一个括号,而括号里会显示出任务数,由于每次任务数的不同,导致对象在添加到对象库后,时常无法正常识别,这时候,可以使用正则表达式来解决。

打开对象库->找到需要使用正则的对象 -> 点击[#]按钮 -> 描述->确定->搞定。
part06_10

描述性编程

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

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

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

QTP支持的正则常用表达式

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

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

part06_09
写了这么多,难免会有疏漏。大家可以留言补充。

PART – 06 END

转载请注明出处与原作者。
如果你觉得文章对你有所帮助,请留言。
如果你想请作者喝杯咖啡,请点这个超链接

4 thoughts on “[PLAYING QTP] PART 06 – OBJECT REPOSITORY

  1. 你好,我看51上说识别机制是强制-辅助-标识-智能,和你这的说法不一……

    1. 你好,前面部分是一样的,先强制,再辅助,后面两个有不一样。这里提供一段以前官网提供的解释,给你做一下参考:When you run a test, QuickTest searches for the object that matches the description it learned (without the ordinal identifier). If it cannot find any object that matches the description, or if it finds more than one object thatmatches, QuickTest uses the Smart Identification mechanism (if enabled) to identify the object. In many cases, a Smart Identification definition can help QuickTest identify an object, if it is present, even when the learneddescription fails due to changes in one or more property values. The test object description is used together with the ordinal identifier only in cases where the Smart Identification mechanism does not succeed in narrowing down the object candidates to a single object.The Object Identification dialog box also enables you to configure new user-defined classes and map them to an existing test object class so that QuickTest can recognize objects from your user-defined classes when yourun your test.

  2. Pingback: 2014世界杯投注

发表评论

电子邮件地址不会被公开。