注:本文最早发表于51testing
揭秘 QTP 保留对象机制
在 QTP 的帮助文档中,介绍了通过 Dictionary 对象来在 Action 之间共享数据的方法,就是在注册表中添加一个保留对象( reserved object ),例如“ GlobalDictionary ”,把 Dictionary 对象作为环境变量来使用,可以在多个 Action 之间共享数据。文档中仅介绍了如何在注册表中添加这个对象的注册信息,实际上还可以设置更多的注册信息,让添加的保留对象更好用、更强大。
本文将深入探索 QTP 的保留对象机制,以及如何利用 QTP 的保留对象机制来简化测试脚本的编写工作。
什么是保留对象?
在 QTP 自动化测试脚本编写过程中,我们通常会使用 QTP 提供的一些函数或对象,例如帮助文档中列出的 Utility 中的对象:
Crypt Object
DataTable Object
Description Object
DotNetFactory Object
DTParameter Object
DTSheet Object
Environment Object
Extern Object
LocalParameter Object
MercuryTimers Object (Collection)
MercuryTimer Object
Parameter Object
PathFinder Object
Properties Object (Collection)
QCUtil Object
RandomNumber Object
Recovery Object
Reporter Object
RepositoriesCollection Object
Repository Object
Services Object
Setting Object
TextUtil Object
TSLTest Object
XMLUtil Object
这些都是 QTP 的保留对象,或者称之为“内置对象”,它们封装了各种常用的函数,对于简化测试脚本的编写起到很大的作用,例如使用 DotNetFactory 这个保留对象就可以方便地访问、创建和使用 .NET 的对象,下面是一个小例子,用于创建 .NET 的 Form 窗体对象,显示一段时间后关闭:
Set var_CreateInstance = DotNetFactory.CreateInstance("System.Windows.Forms.Form", "System.Windows.Forms")
var_CreateInstance.Show
wait 2
var_CreateInstance.Close
注册自定义保留对象
按照 QTP 的帮助文档的提示,我们可以通过修改注册表的方式来添加自定义的保留对象。例如,添加 Dictionary 保留对象的方法如下:
( 1 ) 打开注册表,定位到下面注册项:
HKEY_CURRENT_USER/Software/Mercury Interactive/QuickTest Professional/MicTest/ReservedObjects
实际上,从该注册项所包含的子项可以看到, QTP 的常用保留对象都列在这里了,例如: DataTable 、 DotNetFactory 、 Environment 等。而我们要做的是把一些自定义的保留对象添加进去。
( 2 )添加一个名为“ GlobalDictionary ”的注册项,如图所示:
<!-- [if gte vml 1]><v:shapetype id="_x0000_t75" coordsize="21600,21600" o:spt="75" o:preferrelative="t" path="m@4@5l@4@11@9@11@9@5xe" filled="f" stroked="f"> <v:stroke joinstyle="miter"/> <v:formulas> <v:f eqn="if lineDrawn pixelLineWidth 0"/> <v:f eqn="sum @0 1 0"/> <v:f eqn="sum 0 0 @1"/> <v:f eqn="prod @2 1 2"/> <v:f eqn="prod @3 21600 pixelWidth"/> <v:f eqn="prod @3 21600 pixelHeight"/> <v:f eqn="sum @0 0 1"/> <v:f eqn="prod @6 1 2"/> <v:f eqn="prod @7 21600 pixelWidth"/> <v:f eqn="sum @8 21600 0"/> <v:f eqn="prod @7 21600 pixelHeight"/> <v:f eqn="sum @10 21600 0"/> </v:formulas> <v:path o:extrusionok="f" gradientshapeok="t" o:connecttype="rect"/> <o:lock v:ext="edit" aspectratio="t"/> </v:shapetype><v:shape id="_x0000_i1025" type="#_x0000_t75" style='width:300pt; height:132.75pt'> <v:imagedata src="file:///C:/DOCUME~1/testware/LOCALS~1/Temp/msohtml1/01/clip_image001.png" mce_src="file:///C:/DOCUME~1/testware/LOCALS~1/Temp/msohtml1/01/clip_image001.png" o:title=""/> </v:shape><![endif]--><!-- [if !vml]--><!-- [endif]-->
( 3 )然后添加两个“ REG_SZ ”类型的注册项,分别是:
ProgID :准备创建的 COM 对象的 ID ,在这里就是 Dictionary 对象所对应的 COM 对象名“ Scripting.Dictionary ”。
UIName : QTP 中指向保留对象的名字,在这里输入“ GlobalDictionary ”。
( 4 )然后再添加一个类型为“ REG_DWORD ”的注册项:
VisibleMode :设置 DWORD 值为 2 ,用于控制自动完成( auto-complete )和代码智能感知( intelligence )。
使用自定义保留对象
做完这些设置后,重新启动 QTP ,进入关键字视图,添加测试步骤,在“ Step Generator ”中可以选择“ Utility Objects ”,然后选择已注册的“ GlobalDictionary ”以及其中的各种方法。
<!-- [if gte vml 1]><v:shape id="_x0000_i1026" type="#_x0000_t75" style='width:160.5pt;height:219.75pt'> <v:imagedata src="file:///C:/DOCUME~1/testware/LOCALS~1/Temp/msohtml1/01/clip_image003.png" mce_src="file:///C:/DOCUME~1/testware/LOCALS~1/Temp/msohtml1/01/clip_image003.png" o:title=""/> </v:shape><![endif]--><!-- [if !vml]--><!-- [endif]-->
例如,我们可以选择 Dictionary 对象的 Add 方法,在参数( Arguments )中输入 Key 和 Item 的值。单击“ OK ”,然后在关键字视图中就可以看到新添加的步骤包含的对象:
<!-- [if gte vml 1]><v:shape id="_x0000_i1027" type="#_x0000_t75" style='width:350.25pt;height:219pt'> <v:imagedata src="file:///C:/DOCUME~1/testware/LOCALS~1/Temp/msohtml1/01/clip_image005.png" mce_src="file:///C:/DOCUME~1/testware/LOCALS~1/Temp/msohtml1/01/clip_image005.png" o:title=""/> </v:shape><![endif]--><!-- [if !vml]--><!-- [endif]-->
在专家视图中也可以使用该对象,并且输入对象名,加点号后可以自动弹出对象的方法和属性列表。下面是一个使用 GlobalDictionary 对象的例子:
' 使用 GlobalDictionary 前清空里面的数据
If GlobalDictionary.Count > 0 Then
GlobalDictionary.RemoveAll
End If
' 存储一个数值
DepartDate = " 2008-3-31 "
GlobalDictionary.Add "DateCheck", DepartDate
使用 GlobalDictionary 添加数据后,可在当前 Action 使用 GlobalDictionary 中的数据,也可在另外一个 Action 中使用添加到 GlobalDictionary 的数据,下面脚本从 GlobalDictionary 中读取数据:
Dim CompareDate
CompareDate=GlobalDictionary("DateCheck")
Msgbox CompareDate
探秘 QTP 保留对象注册信息
查看注册表的其它保留对象的信息可知,还有很多其它的项和值可以添加和设置,例如在 Icons 项中设置对象的图标。
<!-- [if gte vml 1]><v:shape id="_x0000_i1028" type="#_x0000_t75" style='width:372pt;height:147pt'> <v:imagedata src="file:///C:/DOCUME~1/testware/LOCALS~1/Temp/msohtml1/01/clip_image007.png" mce_src="file:///C:/DOCUME~1/testware/LOCALS~1/Temp/msohtml1/01/clip_image007.png" o:title=""/> </v:shape><![endif]--><!-- [if !vml]--><!-- [endif]-->
查看 DataTable 对象的 Icons 注册项可看到,图标的数据指向: D:/Program Files/HP/QuickTest Professional/bin/MicParam.dll 这个文件。
用 VisualStudio.NET 2005 打开这个 DLL 可看到 Icon 的信息:
<!-- [if gte vml 1]><v:shape id="_x0000_i1029" type="#_x0000_t75" style='width:251.25pt;height:167.25pt'> <v:imagedata src="file:///C:/DOCUME~1/testware/LOCALS~1/Temp/msohtml1/01/clip_image009.png" mce_src="file:///C:/DOCUME~1/testware/LOCALS~1/Temp/msohtml1/01/clip_image009.png" o:title=""/> </v:shape><![endif]--><!-- [if !vml]--><!-- [endif]-->
双击可打开图标编辑器查看 Icon 的详细信息,例如打开名为“ 135 ”的 Icon ,可看到如图所示的图标。
<!-- [if gte vml 1]><v:shape id="_x0000_i1030" type="#_x0000_t75" style='width:251.25pt;height:167.25pt'> <v:imagedata src="file:///C:/DOCUME~1/testware/LOCALS~1/Temp/msohtml1/01/clip_image011.png" mce_src="file:///C:/DOCUME~1/testware/LOCALS~1/Temp/msohtml1/01/clip_image011.png" o:title=""/> </v:shape><![endif]--><!-- [if !vml]--><!-- [endif]-->
这正是我们通常在 QTP 的步骤产生器( Step Generator )或关键字视图中看到的 DataTable 对象的图标。
<!-- [if gte vml 1]><v:shape id="_x0000_i1031" type="#_x0000_t75" style='width:160.5pt;height:219.75pt'> <v:imagedata src="file:///C:/DOCUME~1/testware/LOCALS~1/Temp/msohtml1/01/clip_image013.png" mce_src="file:///C:/DOCUME~1/testware/LOCALS~1/Temp/msohtml1/01/clip_image013.png" o:title=""/> </v:shape><![endif]--><!-- [if !vml]--><!-- [endif]-->
因此,我们也可以为自定义的 GlobalDictionary 对象添加一个图标,方法如下:
( 1 )在注册表中的 GlobalDictionary 项下添加名为“ Icons ”的注册项。
( 2 )修改默认值,输入包含图标资源的 DLL 所在的文件路径,例如“ D:/Program Files/HP/QuickTest Professional/bin/AQTProductInfo.dll ”,并且在后面添加指定哪个 Icon ,完整的注册项的值为:
D:/Program Files/HP/QuickTest Professional/bin/AQTProductInfo.dll,204,204
( 3 )重新启动 QTP 后,在关键字视图就可以看到 GlobalDictionary 对象的图标已经发生了变化,不再是默认的图标,而是指定 DLL 所包含的图标:
<!-- [if gte vml 1]><v:shape id="_x0000_i1032" type="#_x0000_t75" style='width:319.5pt;height:140.25pt'> <v:imagedata src="file:///C:/DOCUME~1/testware/LOCALS~1/Temp/msohtml1/01/clip_image015.png" mce_src="file:///C:/DOCUME~1/testware/LOCALS~1/Temp/msohtml1/01/clip_image015.png" o:title=""/> </v:shape><![endif]--><!-- [if !vml]--><!-- [endif]-->
使用自定义保留对象来简化代码编写工作
保留对象( Reserved Objects )的机制是 QTP 用于创建单件 COM 对象的内部机制,可以让脚本的编写更加简单。例如,如果不用保留对象的机制,则在 QTP 中使用 Excel 需要按下面代码来实现:
Dim oSheet,arrRange
' 创建 Excel 应用程序对象
Set oExcel = CreateObject("Excel.Application")
' 打开 Excel 文件
oExcel.Workbooks.Open("D:/QTP/MyWork/ReadExcelFileTest1/ObjectTree.xls")
' 获取表格的使用范围
Set oSheet = oExcel.Worksheets("Tree").UsedRange
' 获取从 A 列到 Z 列,从第 1 行到第 1000 行的范围中的所有值
Set oRange = oSheet.Range("A1:Z1000")
' 把 Excel 数据转换到数组
arrRange = oRange.Value
' 关闭工作簿
oExcel.WorkBooks.Item(1).Close
' 退出 Excel
oExcel.Quit
Set oExcel = Nothing
Msgbox arrRange(3,1)
可看到,脚本中需要使用 CreateObject 方法,首先创建名为“ Excel.Application ”的 COM 对象,然后才能使用这个 Excel 中的属性和方法。而如果在注册表中添加了 Excel 对象作为 QTP 的保留对象,则可以使用下面的代码来实现:
Dim oSheet,arrRange
' 打开 Excel 文件
Excel.Workbooks.Open("D:/QTP/MyWork/ReadExcelFileTest1/ObjectTree.xls")
' 获取表格的使用范围
Set oSheet = Excel.Worksheets("Tree").UsedRange
' 获取从 A 列到 Z 列,从第 1 行到第 1000 行的范围 i 中的所有值
Set oRange = oSheet.Range("A1:Z1000")
' 把 Excel 数据转换到数组
arrRange = oRange.Value
' 关闭工作簿
Excel.WorkBooks.Item(1).Close
' 退出 Excel
Excel.Quit
Msgbox arrRange(3,1)
这种使用 Excel 的 COM 接口的方式不仅省去了创建 COM 对象的代码,更重要的是得到了代码智能感知( IntelliSense )的功能,可以查看到 Excel 应用程序中的 COM 对象接口的所有属性和方法,如图所示。
<!-- [if gte vml 1]><v:shape id="_x0000_i1034" type="#_x0000_t75" style='width:276.75pt;height:213.75pt'> <v:imagedata src="file:///C:/DOCUME~1/testware/LOCALS~1/Temp/msohtml1/01/clip_image017.png" mce_src="file:///C:/DOCUME~1/testware/LOCALS~1/Temp/msohtml1/01/clip_image017.png" o:title=""/> </v:shape><![endif]--><!-- [if !vml]--><!-- [endif]-->
这将有助于提高测试脚本的编写效率,让某些 COM 对象的使用更为简单、直接,让我们的自动化测试工程师在编写测试脚本时更加高效,所要做的仅仅是在注册表中添加一些必要的信息即可。
保留对象机制解析
在掌握了自定义保留对象的创建和使用方法后,我们回过头来思考一下 QTP 的保留对象机制:
( 1 ) COM 对象是可以在 QTP 中通过 CreateObject 命令创建的对象,例如 Scripting.Dictionary 、 Word.Application 等。
( 2 )保留对象就是把这些 COM 对象作为 QTP 可自动识别的、已定义的对象来使用,这些对象在 QTP 启动时被加载和创建,并且只创建一次,是单件对象。
( 3 )创建后可以在 QTP 的脚本中直接访问和使用,并且对象可在所有 Action 中共享,类似于全局的变量,可用于替代环境变量( Environment )使用,但是作为对象拥有更丰富的“内涵”,包括各种属性和方法,
( 4 )保留对象可用于简化和组织很多编码工作:文件 IO 、写 Log 、使用 Excel 、 Word 、 Outlook 等,也可以用于替代环境变量,例如用 Dictionary 对象来替代环境变量,而不需要在环境变量中定义大量的变量,而且能利用 Dictionary 对象的灵活结构来存储、编辑和访问大量的数据。
( 5 ) QTP 启动时会自动创建保留对象,例如我们把 Excel 注册到 QTP 的保留对象中,则 QTP 在启动时也会把 Excel 进程也加载,并且可以看到在 QTP 的整个运行过程中, Excel 进程都处于激活状态,可以在 Windows 任务管理器中看到 Excel 的进程,当 QTP 退出时, Excel 进程也会被关闭。因此,在这种方式下使用 Excel 要特别注意 Excel 进程不要被意外关闭,否则将出现如图所示的错误。
<!-- [if gte vml 1]><v:shape id="_x0000_i1033" type="#_x0000_t75" style='width:170.25pt;height:75pt'> <v:imagedata src="file:///C:/DOCUME~1/testware/LOCALS~1/Temp/msohtml1/01/clip_image019.png" mce_src="file:///C:/DOCUME~1/testware/LOCALS~1/Temp/msohtml1/01/clip_image019.png" o:title=""/> </v:shape><![endif]--><!-- [if !vml]--><!-- [endif]-->
小结
本文深入探索了 QTP 的保留对象的机制,介绍了如何创建和使用自定义的保留对象来简化自动化测试脚本的编写工作,提高自动化测试脚本的编写效率。
实际上, QTP 中还隐藏着不少尚未对外公开的“秘密”,有待像我这样的充满“好奇心”的人去挖掘!