51Testing软件测试论坛

 找回密码
 (注-册)加入51Testing

QQ登录

只需一步,快速开始

微信登录,快人一步

手机号码,快捷登录

查看: 3819|回复: 10
打印 上一主题 下一主题

[原创] QTP描述性编程(descriptive programming)

[复制链接]

该用户从未签到

跳转到指定楼层
1#
发表于 2010-10-11 15:33:43 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
1 、 descriptive programming 概述
通 常情况下,当在录制一个操作时, QTP 会将被操作对象加入到对象库里( Object Repository )。一旦对象存在于对象库里,我们就可以在专家 视图里通过添加相关的对象方法来对该对象进行操作。我们可以通过引用层次型对象库里的对象描述( Object Description )来添加相应的方 法。因为 QTP 对象库中的每个对象都具有唯一名称,所以在引用时对象名是必须需要指定的。然后在测试运行期间, QTP 在对象库中根据这个对象的名称和父对象来查找对象,并使用为这个测试对象存储的测试对象描述,在网站或应用程序中标识该对象。
例 如我们用 QTP 录制 Yahoo Mail 登录情况时我们需要输入用户名,于是在录制时我们就会录下一个 WebEdit 对象,它的缺省逻辑名为 “login” ,该编辑字段位于名为 “Yahoo! Mail - The best”  的页面上,并且该页面在浏览器中使用名称 Yahoo! 进行录制。
那么如果我们想要应用该对象,就可以在专家视图输入以下信息:
Browser("Yahoo!").Page("Yahoo! Mail - The best").WebEdit("login").Set “xxx” 或者我们也可以调用一些方法,获取改对象在运行时的对象名,如:
Browser("Yahoo!").Page("Yahoo! Mail - The best").WebEdit("login").GetROProperty(“name”) 然 而,我们可以发觉到,上面的例子在处理对象时,对象已经存在于对象库里,因此我们可以应用这个对象的逻辑名。实际使用中,情况往往并非如此简单,我们经常 会遇到很多在页面上动态产生的对象,换而言之,对象库里没有这些对象,我们也无从引用。因此我们必须采用其他的技术来完成这类操作,这也就是我们需要讲解 的 Descriptive Programming 。为了满足上面提到的动态对象的处理问题, QTP 允许用户通过将对象属性编码到测试脚 本里来动态识别对象,这就是我们通常意义下称为的 Descriptive Programming 。通过这种方式,我们可以指示 QTP 不通过引用对象库和 对象名来对实际对象进行操作。具体操作中,我们只需要为 QTP 提供对象的一组属性和值,这样 QTP 就可以来识别相应的对象并对其进行操作。这相当于,告诉 QTP 要识别对象的一些关键特征,根据这些特征 QTP 就可以一一匹配然后识别出来这个对象。而且,更为重要的是,通过这种 Descriptive Programming 的方式,还可以让 QTP 识别具有某些相同属性的对象。我们先来举个例子来看一下:我们假设当前的 Windows 系统中打开了若干的 Yahoo 主页面(多于一个),现在我们要关闭所有的正在浏览 Yahoo 主页面的浏览器。对于上面那个例子来说,我们先看一个简单一点的情况,假设只有且仅有一个 Yahoo 主页面:那么我们可以用下面的方法来
Window("Text:=Yahoo! - Microsoft Internet Explorer").Close 我 们可以看到语句里我们要查找的对象是 Window 窗口标题为 “Yahoo! - Microsoft Internet Explorer” ,然后把它关 闭,具体的语法说明我们稍后为解释。但是上面的语句仅仅适合前面提到的条件 “ 只有且仅有一个 Yahoo 主页面 ” ,如果有多个同样的窗口就会出错,原因是通 过语句可以匹配到多个对象,而 QTP 不知道应该对哪个对象进行关闭动作。我们需要进一步的缩小匹配范围:
Dim i
i = 0
while (Window("Text:="Yahoo!" - Microsoft Internet Explorer", "index:="&i).exist)
Window("Text:=Yahoo! - Microsoft Internet Explorer", "index:="&i).close
i = i +1
wend 这里我们可以看到,对于具有相同属性的对象,我们可以通过 index 参数来对其进行区别,第一个对象为 index=0 ,第二个为 index=1 等等,依次类推。当然我们还可以通过 CreationTime 和 Location 参数来定位对象,这里就不详细叙述了。
通 过上面的例子,我们对 Descriptive Programming 有一个基本了解了,下面我们详细讲解一下 Descriptive Programming :在具体实现中,我们有两种类型的 Descriptive Programming 方法。可以列出直接在 测试语句中描述对象的属性和值的集合;或者向 Description  对象中添加属性和值的集合,然后在语句中输入 Description  对象的名称。 下面我们分别举例介绍。
2 、直接在语句中输入编程描述通过多个指定描述对象的 property:=value 对,可以直接在语句中描述对象,这是最直接有效的方法。常规语法为:
TestObject("PropertyName1:=PropertyValue1", "..." , "PropertyNameX:="PropertyValueX""}  
TestObject -  测试对象的类。
PropertyName:=PropertyValue -  测试对象的属性及其值。各个 property:="value"  对之间应用逗号和引号分开。例如:以下语句指定 Mercury Tours  页面中名为 author 且索引值为 3  的 WebEdit  测试对象。当测试运行时, QTP  将查找具有匹配属性值的 WebEdit  对象,并输入文本 jojo 。
Browser("Mercury Tours").Page("Mercury Tours").WebEdit("Name:="Author"", "Index:="3"").Set "Mark Twain"  我们也可以从从描述中的特定位置(从 Page  对象描述开始)开始使用 Descriptive Programming 。
Browser("Mercury Tours").Page("Title:="Mercury" Tours").WebEdit("Name:="Author"", "Index:="3"").Set "jojo"  此外,如果我们希望在在一个测试或组件中多次使用相同的 Descriptive Programming ,则可以将创建的对象赋值给变量,这样使用会方便很多。
例如:我们需要完成下面一系列操作
Window("Text:=HyperSna").WinButton("Caption:= 日期 ").Click
Window("Text:=HyperSna").WinButton("Caption:= 时间 ").Click
Window("Text:=HyperSna").WinButton("Caption:= 确定 ").Click 那么,为了方便其见,我们可以将 Window("Text:=HyperSna") 赋值到一个变量,然后再使用,参见下面的代码:
Set WinHyper = Window("Text:="HyperSna"")  
WinHyper.WinButton("Caption:= 日期 ").Click
WinHyper.WinButton("Caption:= 时间 ").Click
WinHyper.WinButton("Caption:= 确定 ").Click
如果使用了 VBScript 里面的 With 语句,还可以简化为以下代码:
With Window("Text:="HyperSna"")  
.WinButton("Caption:= 日期 ").Click  
.WinButton("Caption:= 时间 ").Click
.WinButton("Caption:= 确定 ").Click
End With  
下面我们来看一个更为详细的例子,在 QTP 产品缺省安装里面自带了一个网上订机票的示例称为 Mercury Tour ,我们看一下在订票过程中何时需要用 Descriptive Programming 。首 先登入系统后,如果需要订票,就要先搜索航班,此时系统要求输入订票乘客的数量,假设我们在第一次录制脚本时选择了 1 个 Passenger ,并成功完成订 票。然后,我们需要参数化乘客数量来测试订票系统,我们会发现回放会失败。原因在于,不同的乘客的数量导致在订票时需要输入每个乘客的姓名,而录制时,只 输入了一个乘客的姓名。而乘客姓名的输入框是随着乘客数量的变化而动态生成的,我们不可能从对象库里得到没有录制的对象,因此必须使用 Descriptive Programming 。
在录制单个乘客时,我们得到的录制语句是:
Browser("Welcome: Mercury Tours").Page("Book a Flight: Mercury").WebEdit("passFirst0").Set "Michael"
Browser("Welcome: Mercury Tours").Page("Book a Flight: Mercury").WebEdit("passLast0").Set "Wang"
显然 WebEdit("passFirst0") 和 WebEdit("passLast0") 是录制时产生的对象并存放到对象库里的。通过对象库,我们可以看到对象的属性如下
系 统对于发生多个 FirstName 时,命名规则是 passFirst0 , passFirst1… 依次类推。因此只要通过简单的 Descriptive Programming 就可以完成动态 FirstName 与 LastName 的识别工作。这里我们假设参数化的乘客数已经赋值给 intPassNum ,下面是脚本中的关键语句:
counter = 0
For i = 0 to (intPassNum)
Browser("Find a Flight:").Page("Book a Flight:").WebEdit("name:="passFirst""&i).Set "Michael"
Browser("Find a Flight:").Page("Book a Flight:").WebEdit("name:="passLast""&i).Set "Wang"
counter = counter + 1
Next
3 、使用 description 对象
使 用 Description  对象可以返回包含一组 Property  对象的 Properties  集合对象。 Property  对象由属性名和值组成。然 后,可以在语句中指定用返回的 Properties  集合代替对象名。(每个 property  对象都包含一个属性名和值)。
要创建 Properties  集合,可以使用以下语法输入 Description.Create  语句:
Set MyDescription = Description.Create()  
创 建 Properties  对象(例如,以上示例中的 MyDescription )后,就可以输入语句,以便在运行会话期间在 Properties  对象中 添加、编辑、删除或检索属性和值。这样,就可以在运行会话期间,使用动态方法确定哪个属性以及多少个属性应包含在对象描述中。
在 Properties  集合中填充一组 Property  对象(属性和值)后,可以在测试语句中指定用 Properties  对象代替对象名。
例如,假设我们需要完成以下一个操作:
Window("Error").WinButton("text:=OK", "index:="1"").Click
我们可以通过 Description 对象来实现同样的功能,参加下面的代码:
Set MyDescription = Description.Create()
MyDescription("text").Value = "OK"
MyDescription("index").Value = 1
Window("Error").WinButton(MyDescription).Click
Set MyDescription = Nothing
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏
回复

使用道具 举报

该用户从未签到

2#
 楼主| 发表于 2010-10-11 15:34:00 | 只看该作者
自己顶一下
回复 支持 反对

使用道具 举报

该用户从未签到

3#
发表于 2010-10-16 09:49:38 | 只看该作者
Browser("Title:=百度一下,你就知道").Page("Title:=百度一下,你就知道").WebEdit("name:=wd").Set "我的中国心"
Browser("Title:=百度一下,你就知道").Page("Title:=百度一下,你就知道").WebEdit("name:=wd").Submit
Browser("Title:=百度一下,你就知道").Page("Title:=百度搜索_我的中国心").Link("Text:=我的中国心_百度百科").Click
呵呵,问一下这样的描述第三行为什么会有问题呢
回复 支持 反对

使用道具 举报

该用户从未签到

4#
发表于 2010-10-16 09:55:02 | 只看该作者
楼上的好像不会有问题
回复 支持 反对

使用道具 举报

该用户从未签到

5#
发表于 2010-10-18 11:10:28 | 只看该作者
好东西,要顶
回复 支持 反对

使用道具 举报

该用户从未签到

6#
发表于 2010-10-18 17:36:51 | 只看该作者
回复 支持 反对

使用道具 举报

  • TA的每日心情
    开心
    2016-2-27 08:48
  • 签到天数: 2 天

    连续签到: 1 天

    [LV.1]测试小兵

    7#
    发表于 2010-10-19 12:54:32 | 只看该作者
    Browser("Title:=百度一下,你就知道").Page("Title:=百度一下,你就知道").WebEdit("name:=wd").Set "我的 ...
    zhaoshenzhou 发表于 2010-10-16 09:49


      把 第三行中的 Text 改为 text 再试试
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    开心
    2016-2-27 08:48
  • 签到天数: 2 天

    连续签到: 1 天

    [LV.1]测试小兵

    8#
    发表于 2010-10-19 12:55:41 | 只看该作者
    如果还不行 那么使用对象的 Exist 属性 判断一下你用描述性编程写的对象是否存在。
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    开心
    2016-2-27 08:48
  • 签到天数: 2 天

    连续签到: 1 天

    [LV.1]测试小兵

    9#
    发表于 2010-10-19 12:57:27 | 只看该作者
    非常感谢楼主的奉献。现在难得有人能静下心来 写些这样高质量的 总结性的帖子里。
    回复 支持 反对

    使用道具 举报

    该用户从未签到

    10#
     楼主| 发表于 2011-4-8 09:35:36 | 只看该作者
    QTP中使用描述性编程
      ● 使用编程性描述(Using Programmatic Descrīptions)

      在录制脚本时,QTP会将被测对象添加到对象仓库中。只要对象存在于仓库中,我们就可以在专家视图中使用该对象进行手动添加脚本。在脚本中,我们一般都使用对象的名称(该对象名称不区分大小写)作为对象描述。

      例如:

      在下面的语句中“username”是一个编辑框的名称。这个编辑框位于某页面(Page)之上(该页面的名称为“Mercury Tours”),并且该页面属于名为“Mercury Tours”的浏览器(browser)。

      Browser("Mercury Tours").Page("Mercury Tours").WebEdit("username")

      因为对象仓库中的对象的名称是唯一的,因此你只要在脚本中指定对象的名称即可。QTP根据指定的对象名称以及它的父对象在对象仓库中找到该对象,然后根据仓库中对象的详细描述从被测试程序中查找并识别对象。

      其实,在QTP脚本中,不使用对象仓库或对象名称,也可以对被测程序中的对象进行操作。为了做到这一点,我们需要在QTP脚本中提供对象的属性及其值的列表。这就是编程性描述。

      当对象不存在于对象仓库之中,而我们又希望操作该对象时,编程性描述就非常有用。如果有多个对象,它们具有某些相同的属性,通过编程性描述,我们可以在这些对象上进行相同的操作;或者某个对象的属性无法确定,需要在运行过程中指定,我们也可以使用编程性描述,来对该对象进行操作。

      例如:在一个页面有多个check box,你不能预知其个数,也不知道所有check box的准确描述,然而你希望选中所有的check box。在这种情况下,你可以使用编程性描述来解决。你只需要让QTP对所有描述为HTML TAG=input,TYPE=check box的对象执行一个Set “ON”的操作即可。

      编程性描述的方法有两种:

      方法一:在语句中直接列出对象的属性及值的列表;

      方法二:使用Descrīption对象,为Descrīption对象添加属性及值的集合,然后在语句中直接使用Descrīption对象的名称即可。

      使用第一种方法要简单一些,但是在很多情况下,第二种方法更显得功能强大并更有效率。

      ● 在语句中直接使用编程描述(Entering Programmatic Descrīptions Directly into Statements)

      在语句中不使用对象的名称,而是使用对象的描述(指定多对property:=value值)。

      通常语法如下:

      TestObject(“PropertyName1:=PropertyValue1”,“…”,“PropertyNameX:=PropertyValueX”)

      TestObject:指的是测试对象的类名

      PropertyName:=PropertyValue:指的是测试对象的属性及值。每对property:=value用双引号标记,并用逗号隔开。

      注:property value可以是变量。

      注意:在编程性描述中,QTP将所有的property value视为正则表达式。因此,当property value中包括正则表达式特殊字符(如*,?,或+)时,要在特殊字符前加“\”。

      下面的语句中,使用到了Mercury Tours网页中的一个WebEdit对象,它的Name为Author,Index为3。在运行过程中,QTP就会从网页中查找Name为Author并且Index为3的WebEdit对象,并在WebEdit中输入文字“MarkTwain”。

      Browser("Mercury Tours").Page("Mercury Tours").WebEdit("Name:=Author", "Index:=3").Set "Mark Twain"

      注意:如果你对测试对象层级关系中的某个上级对象使用了编程性描述,那么在同一语句中,从该对象开始,它的所有下级对象都必须使用编程性描述,否则QTP不能识别该父级对象的下级对象。

      例如:语句中,层级关系中所有的对象都使用了编程性描述:

      Browser("Title:=Mercury Tours").Page("Title:=Mercury Tours").WebEdit("Name:=Author", "Index:=3").Set "Mark Twain"

      下面的语句中,从层级关系中的某个点开始,使用编程性描述(从Page对象开始):

      Browser("Mercury Tours").Page("Title:=Mercury Tours").WebEdit("Name:=Author", "Index:=3").Set "Mark Twain"

      但是,你不能象下面的语句这样使用编程性描述。(它对Browser及Page对象使用了编程性描述,但是对于WebEdit对象,却又想使用对象仓库中的名称)

      Browser("Title:=Mercury Tours").Page("Title:=Mercury Tours").WebEdit("Author").Set "Mark Twain"

      QTP偿试根据WebEdit的名称在仓库中定位对象,但是却无法在仓库中找到它的父对象。

      For more information on working with test objects, seeWorking with Test Objects。

      如果在脚本中你要多次使用到相同的编程性描述,可以将对象指定到变量。

      例如,有如下脚本:

      Window("Text:=Myfile.txt - Notepad").Move 50, 50

      Window("Text:=Myfile.txt - Notepad").WinEdit("AttachedText:=Find what:").Set "hello"

      Window("Text:=Myfile.txt - Notepad").WinButton("Caption:=Find next").Click

      你可以将脚本改进为:

      Set MyWin = Window("Text:=Myfile.txt - Notepad")

      MyWin.Move 50, 50

      MyWin.WinEdit("AttachedText:=Find what:").Set "hello"

      MyWin.WinButton("Caption:=Find next").Click

      你还可以使用With语句,将脚本改进为:

      With Window("Text:=Myfile.txt - Notepad")

      .Move 50, 50

      .WinEdit("AttachedText:=Find what:").Set "hello"

      .WinButton("Caption:=Find next").Click

      End With

      For more information about theWithstatement, seeWith Statement。

      ● 在编程性描述中使用Descrīption对象(Using Descrīption Objects for Programmatic Descrīptions)

      你可以使用Descrīption对象,来返回一个Properties collection对象,该集合对象包括一系列Property对象。每个Property对象由Property name及value组成。

      然后在语句中用Properties collection对象替代被测对象的名称。

      注意:默认情况下,所有被添加到Properties collection中的Property对象的值被当成正则表达式对待。因此,当Property Value中包含正则表达式的特殊字符(如*,?,+)时,要在特殊字符前使用“\”符号。

      你也可以在Properties Collection中,将RegularExpression属性值设置为False,这样即使在Property Value中用到了正则表达式的特殊字符,也会被视为普通字符。更多信息参考QuickTest Professional Object Model Reference的Utility部分。

      要创建Properties collection,使用Dexcription Create语句,语法如下:

      SetMyDescrīption= Descrīption.Create()

      一旦创建了Properties对象(例如上例中的Mydescrīption),在运行过程中,你就可以使用语句向Properties对象添加、编辑、移除或获取属性及属性值。这使你在运行过程中可以动态的决定:在对象描述中使用哪些属性、使用多少属性。

      当你将一系列的属性及属性值加入到Properties collection中以后,你就可以在脚本语句中用Properties对象替代被测对象的名称。

      例如,有如下语句:

      Window("Error").WinButton("text:=OK", "width:=50").Click

      通过改造,成为:

      Set MyDescrīption = Descrīption.Create()

      MyDescrīption("text").Value = "OK"

      MyDescrīption("width").Value = 50

      Window("Error").WinButton(MyDescrīption).Click

      注:当为一个ActiveX对象创建编程性描述时,如果该对象的run-time对象是windowless的(即没有相应的window handel),就必须在属性描述中将它的windowless property设置为Ture。

      例如:

      Set ButDesc = Descrīption.Create

      ButDesc("ProgId").Value = "Forms.CommandButton.1"

      ButDesc("Caption").Value = "OK"

      ButDesc("Windowless").Value = True

      Window("Form1").AcxButton(ButDesc).Click

      ● 对WebElement对象使用编程性描述(Using Programmatic Descrīptions for the WebElement Object)

      如果没有录制WebElement对象,也可以使用编程性描述,来对Web网站中的任何一个WebElement对象进行操作。

      例如:

      Browser("Mercury Tours").Page("Mercury Tours").WebElement("Name:=UserName", "Index:=0").Click

      或

      set WebObjDesc = Descrīption.Create()

      WebObjDesc("Name").Value = "UserName"

      WebObjDesc("Index").Value = "0"

      Browser("Mercury Tours").Page("Mercury Tours").WebElement(WebObjDesc).Click

      QuickTest clicks on the first Web object in the Mercury Tours page with the nameUserName。

      关于WebElement对象的更多信息,参考QuickTest Professional Object Model Reference。

      ● 在编程性描述中使用Index属性(Using the Index Property in Programmatic Descrīptions)

      在需要唯一识别一个对象时,index属性有时候可能非常有用。index属性是对象在源代码中出现的顺序,第1次出现时,index值为0。

      Index属性是object-specific的。因此,当你用index属性值“3”来描述一个WebEdit对象时,QTP会在被测程序的当前页面中查找第4个WebEdit对象。

      如果你使用index属性值3来描述一个WebElement对象时,QTP会在被测程序的当前页面中查找第4个Web对象。

      例如,当前页面中存在下面的对象:

      * 一个名为Qpple的Image对象

      * 一个名为UserName的Image对象

      * 一个名为UserName的WebEdit对象

      * 一个名为Password的Image对象

      * 一个名为Password的WebEdit对象

      下面的语句中指的是列表中的第3个对象,因为它要求指向的是第1个名为UserName的WebEdit对象。

      WebEdit("Name:=UserName", "Index:=0")

      下面的语句中指的是列表中的第2个对象,因为它要求指向的是第1个名为UserName的WebElement对象。

      WebElement("Name:=UserName", "Index:=0")

      注:如果当前只有一个对象,使用index=0将无法查找到对象,因此就不能在对象描述中使用index属性。
    回复 支持 反对

    使用道具 举报

    该用户从未签到

    11#
    发表于 2011-4-11 16:09:16 | 只看该作者
    请问一下,类似这段:
    Browser("Mercury Tours").Page("Title:="Mercury" Tours").WebEdit("Name:="Author"", "Index:="3"").Set "jojo"

    Page("**"M"**")为什么里面还套了个引号""呢?作用是什么?为什么我一用这种格式,QTP就报错,说我缺少")"呢?
    回复 支持 反对

    使用道具 举报

    本版积分规则

    关闭

    站长推荐上一条 /1 下一条

    小黑屋|手机版|Archiver|51Testing软件测试网 ( 沪ICP备05003035号 关于我们

    GMT+8, 2024-11-20 12:40 , Processed in 0.068007 second(s), 25 queries .

    Powered by Discuz! X3.2

    © 2001-2024 Comsenz Inc.

    快速回复 返回顶部 返回列表