第一章
简介
什么是自动化测试
自动化测试是对一个已有的手工测试过程减少并尽可能排除人工干预的过程。
1、什么时候适合做自动化测试
下面是一组适合将手工测试自动化的考量因素:
测试需要经常重复。
测试流程和验证点相对长时间比较稳定。
测试目的是验证一个业务流程,而不是外观,感觉,颜色,图表布局等。
测试需要大量重复或者同时包含很多步骤,并且这些操作每次都需要完全一致,这就要求手工测试者不能疲劳大意。
测试生成的结果被监管机构要求电子化记录和存档并符合正式的证据要求。
测试通过或失败的结果相当容易判断且被所选自动化工具捕获。
测试需要使用大量的数据到被测应用程序中。
2、什么时候需要避免自动化
随机性测试,领域专家在各种业务流程组合中的随机尝试。
一次性测试或者只重复数次。
测试需要覆盖多个功能模块且这些功能模块在整个产品功能中的测试覆盖几乎非常小。
测试验证外观,感觉,颜色,图表的布局等。
测试结果是否通过需要从多个不同并且不相关的系统或(和)应用中判断
自动化测试流程
理解自动化测试中包含的各个阶段对于开发和有效利用测试框架以及用例非常重要:
1、选择“最适合的”自动化工具:在对任何应用开始自动化测试之前,重要的是针对主要应用部分选择最适合的工具。选择需要基于各种因素,比如价格,易用性,应用支持能力和产品服务支持。
2、概念证明(POC):此阶段包含创建一些脚本示例用来在一两个最重要的被测应用中验证业务流程。它可以帮助识别未来在测试用例的脚本开发中有可能碰到的主要问题。概念证明也可用来为你的应用选择最适合的自动化测试工具。
3、需求分析:包含分析某个应用的需求,研究已有的手工测试用例和定义当前自动化测试项目的范围。
4、项目估算:一旦自动化范围定义好,项目估算就可以根据各种因素,如需要自动化的测试用例数量,复杂程度,需开发的可复用模块,人员需求等制定下来。
5、框架设计:包含创建共享对象库,重用模块,编写最佳实践参考文档,以及实现任何可以对开发自动化测试脚本有用的基础支持组件。
6、测试脚本开发:通过调用可重用模块和在工作流具体脚本中增加相关验证点来创建测试用例。
7、调试:完成的测试脚本应该是经过调试的,以保证运行时符合预先设计。要确保在调试时使代码经过所有错误处理路径。
8、执行:在这个阶段测试脚本最终在回归测试中执行来验证被测应用。
9、结果分析:此阶段流程依据执行时生成的各个测试结果。
10、维护:这个阶段包括更新脚本来解决执行中发现的代码问题,其中可能包含UI或结构变动,或者是流程,功能以及新版本中不可避免的变更。一个设计良好的框架和测试集可以保证维护成本达到最小。
第三章、对象库
QTP在对象库(OR)里为每一个被测对象存储了一个对象定义。该定义包含了一些用来唯一识别运行时对象的参数值。QTP
Object Repository Manager 是用来查看和修改对象库中的对象及其属性的。
图 3-1. Object Repository
Manager
图3-1,展示了一个简单的对象库。这个对象库有一个WinToolbar对象,包含了一个可以用来识别的逻辑名"Running
Applications"和两个属性:"Text" 和"nativeclass"
.我们可以点击"Add/Remove"按钮来添加或者删除属性。图3-2显示了从Object
Identification打开的Add/Remove Properties对话框,它可以用来添加或删除任意的属性。
提示:在对象库的树视图中选择一个对象后,点击'Highlight'按钮,应用程序(必须是打开的)中的对象将会高亮显示。同样,在代码中也可以实现高亮:Window("Window").WinToolbar("Running
Applications").Highlight.
图3-2.Add/Remove Properties
对象是如何被添加到对象库的?
对象可以通过两种方式添加到对象库:
1、通过录制与被测应用程序的交互过程添加。
2、手工添加一个或多个对象。
我们可以点击"Add Objects"按钮,然后点击我们要添加的对象,通过这种方式,我们便可以手工添加对象到对象库中。
注意:假如我们要添加的对象是在鼠标点击之后才出现,那么我们可以先按下Ctrl键,然后再去点击。这个方法可以让我们临时屏蔽对象选择模式,从而进行鼠标操作。一旦我们准备好了要添加的对象,就可以放开Ctrl键,进行添加了。
如果我们需要在应用程序间切换,可以先按住Ctrl+ALT键去屏蔽对象选择模式,然后使用例如Alt+Tab键来在不同的应用程序间切换,完成切换后,再次按下Ctrl+ALT键后便可进入对象选择模式并添加对象了。
对象一旦被选中,便会在对象选择窗口中出现
图3-3.对象选择
本对象选择窗口显示了Web页面上的完整的对象结构。选择你需要添加的对象然后点"OK"键就可以了。
小提示:对象选择窗口显示的对象可能会和录制到对象库的不一致。QTP只保留能识别对象的必须的对象结构,这样就可以在测试脚本使用对象时,减少代码的长度。
如果我们选择一个Page对象,然后继续,QTP就会询问我们是否要添加它的子对象。
图 3-4. 对象选择
选择Selected object and all its descendants这个单选按钮,然后点击OK,
页面上所有的对象都会被添加到对象库中去。
提示:对象库不能添加页面上的隐藏对象。
测试对象和运行时对象
测试对象(TO):测试对象是QTP定义的一些类,用它们来代表被测应用的各种对象。
运行时对象(RO):运行时对象是实际的被测应用的对象,是测试执行过程中,TO用来关联的对象。
理解这两种对象类型的区别是非常重要的。可以看成两辆车;车A和车B,QTP能在脚本里用一辆车的测试对象来描述出两辆车A和B。除此之外,每个测试对象也提供了用来和运行时对象交互时相关联的方法和属性。
比如Start,Run和Stop都是汽车对象提供的有用的方法。
TO属性
测试对象的属性是QTP为了识别在测试执行过程中的运行时对象而保留在对象库中的属性。QTP提供GetTOProperties方法来列举对象的所有的TO属性.GetTOProperty和SetToProperty则分别用了读取和修改TO的属性值。
问题 3-1. Test Object 属性的使用
'获取webeidt对象
Set oWebEdit = Browser("").Page("").WebEdit("")
'获取webedit对象封装属性集合
Set TOProps = oWebEdit.GetTOProperties()
Dim i, iCount
iCount = TOProps.Count - 1
'遍历所有封装属性
For i = 0 ToiCount
'获取属性名
sName = TOProps(i).Name
'获取属性值
sValue = TOProps(i).Value
'检查是否为正则表达式
isRegularExpression = TOProps(i).RegularExpression
'显示结果
MsgboxsName&"->" &sValue&"->" &isRegularExpression
Next
|
问题 3-2. 运行时改变Test Object 属性
'获取webedit对象
Set oWebEdit = Browser("Browser").Page("Page").WebEdit("txtName")
'获取webedit的name封装属性值
oldName = oWebEdit.GetTOProperty("name")
'变更webedit对象的name封装属性
oWebEdit.SetTOProperty"name","new value"
'获取已修改的属性
newName = oWebEdit.GetTOProperty("name")
MsgBoxnewName
|
问题 3-3. 测试中获取运行时对象属性
'x为WebEdit对象运行时的value属性值
x = Browser("").Page("").WebEdit("").GetROProperty("value")
MsgBoxx
|
提示:QTP不提供修改运行时对象属性的方法。换言之,没有SetROProperty这个方法。同样,
不同的测试对象都有一个它支持的属性列表,在QTP帮助的对象模型参考中可以找到。
对象库模式
有两种对象库,更确切的说是对象库模式。
图 3-5. 每个Action的对象库设置
每个Action对应的公共对象库
对象探测器 (Object Spy)
对象探测器是用来查看对象所支持的方法和属性。启动对象探测功能:Tool->Object
Spy…
点击指针按钮,然后选择一个对象。当选择了Test Object Properties按钮,属性标签页中就会显示出所有可得到的TO属性,并且在方法标签页中会显示所有可获得的方法,如图3-6
图 3-6. 对象探测对象属性
若选择了Run-time Object Properties按钮,那么将会显示对象的实际属性或方法,如图3-7
Figure 3-7. 对象探测实际属性
大多数的属性值可以通过GetROProperty方法获得。想要了解对象支持的所有属性,可以参考QTP手册。
'获取对象运行时的outerhtml封装属性值
sOuterHTML = Browser("").Page("").WebEdit("").GetROProperty("outerhtml") |
小提示:对象探测器不会显示出任何带有序数识别的属性,例如CreationTime,
index or location.
它们只能在添加到对象库以后计算出来。
对象识别(Object Identification)
对象识别是实现测试脚本的关键部分。QTP不能随意的录制对象,它在记录对象的一组属性时是遵循一定结构的。我们可以更改这些属性,以适应应用程序。更改设置可以在
Tools->Object Identification…
有三种类型的属性可以被QTP用来识别对象:
1、强制属性 - 强制属性总是被捕捉并保存,即使没有其中的一些属性,对象也能识别也不例外。
2、辅助属性 - 假如强制属性不足以唯一识别某对象,那么可以依次添加辅助属性,直到对象可以唯一识别。
3、顺序标识符 - 一旦在使用了强制属性和辅助属性后,对象仍然不能唯一识别,那么可以使用序数识别。有三种类型的序数识别:
图3-8 对象识别设置
图3-8 显示了WebCheckBox的强制属性和辅助属性。
小提示:这些设置是常规的全局设置,并不基于任何脚本。我们可以根据需要添加和删除。
用户定义的对象
QTP使用窗体的类名来识别对象的类型。假如我们的应用程序没有使用标准的窗体类,那么QTP就可能无法正确识别对象。Windows的搜索对话框有一些CheckBox放在了自定义的控件内,当我们试图添加他们到QTP对象库中时,它们只能被识别为WinObject,如图3-9所示。这是由于Qtp不能把这些CheckBox识别成一般的测试对象。
图3-9 搜索窗口中的CheckBox识别成了WinObject
因此我们需要在QTP设置中,把这个CheckBox映射成WinCheckBox.打开Tools->Object
Identification ,然后选择标准Windows环境,点击User Defined按钮,就会弹出映射对话框。点击手型按钮,然后点击CheckBox后,类名就被添加,并且我们可以映射到CheckBox,如图3-10所示。点击Add按钮添加这个映射。
3-10用户自定义对象映射
映射后,QTP便可识别这个对象为WinCheckBox,如图3-11所示。
图3-11 用户自定义对象识别为Checkbox
对象库的不足
作者认为QTP 8.x的对象库有一些不足:
1)对象库管理器不允许批量更新对象属性到脚本。
2) 其他对象下面的对象不能被删除或复制。
3)当一个框体(frame)被加入到了被测的应用程序中时,那么整个测试脚本都要重新录制。
4)当重新录制一个页面或者窗体时,完全一样的对象经常会重复添加,因此,会创建很多相同的页面或窗体:Page_1,
Page_2诸如此类。有时候这个问题可以通过更改Web设置来解决,
打开Tools->Options…Web(Tab)->Page/Frame Options…然后更改设置如图3-12所示
图3-12页面和框体选项
小提示:以上所述的大多数的不足在 QTP9.x中已经得到解决
第九章库函数文件
库函数文件是包含VBScript脚本的纯文本格式文件,用来声明方法,变量,类等。库函数文件可以用任意后缀名,最常用的是VBS或者TXT。库函数文件可以用来组织存放不同功能的代码。它提供了在不同的QTP脚本中分享代码的方法。下面两节介绍加载库函数文件的两种方法。
关联一个全局库函数文件
通过这种方式库函数文件的同一实例可以被当前测试的所有Action共享和访问。如图9-1,打开
Test->Settings… ->Resources (标签页),添加库函数文件。
图9-1 Test Resource配置
小提示1:多个库函数文件加载顺序是从下到上。如果有两个库函数文件包含相同函数,那么会使用更靠近顶部的。
小提示2:如果库函数文件B依赖库函数文件A中的内容,库函数文件A应在列表中更靠近底部。
小提示3:QTP使用全路径名存放库函数文件。作为推荐选项,我们可以使用文件相对路径,如"..\test.vbs"
运行时动态加载本地库函数文件
QTP提供ExecuteFile方法可以在运行时动态加载库函数文件。使用这种方法时库函数文件及其内容只能在ExecuteFile执行的那个Action中可见。下面是一些例子:
'通过绝对路径加载库函数文件
ExecuteFile "C:\Test.vbs"
'通过相对路径加载库函数文件
currentTestDir = Environment("TestDir")
vbsFilePath = currentTestDir& "\..\..\CommonLibs\Test.vbs"
ExecuteFilevbsFilePath
'从Quality Center加载库
ExecuteFile "[QC-ATTACH];;Subject\CommonLibs;;\Test.vbs"
|
小提示:如果ActionA和ActionB都通过ExecuteFile加载了test.vbs,同时ActionA调用ActionB,要注意他们对于所有test.vbs的变量和方法都只使用自己的副本和单独实例。
运行时动态加载全局库函数文件
如之前描述,在一个Action中直接使用ExectueFile方法只能使库函数文件在当前Action可见。但是每个QTP测试脚本可能需要一组全局库,使得对其中所有的Action都可用。取代直接在Action中使用ExecuteFile来加载库的方法,我们在某个全局库中加载库函数文件,那么它将对所有Action可用。
'C: \LibLoader.vbs
Public Function ExecuteFileGlobal (ByValfileName)
ExecuteFilefileName
End Function
|
我们可以将以上代码保存在一个VBS文件中并跟测试关联,使得在任意Action中都能通过调用ExecuteFileGlobal方法来加载文件。这样加载的文件在所有Action中都可以使用。
'在全局区域加载文件
ExecuteFileGlobal "C:\Test.vbs"
|
但是当多个Action反复调用ExecuteFileGlobal会使某个库函数文件加载多次,这样每次都会破坏当前库函数文件中的全局变量的状态。
这个问题可用使用下面的方法解决。我们给ExecuteFileGlobal方法增加一个加载标记,当它为False时库函数文件就不会加载。可以通过给所有使用ExecuteFileGlobal方法加载的库函数文件创建一个全局字典来实现。库函数文件的路径用来判断这个库是否被加载过。
'C: \LoadLibrary.vbs
Dim loadedFiles
Set loadedFiles = CreateObject("Scripting.Dictionary")
loadedFiles.CompareMode = vbTextCompare
'ExecuteFileGlobal方法动态加载文件
'Inputs - strFile: 需加载的完整文件名
' reload: 是否重新加载已载入的文件
Public Function ExecuteFileGlobal (ByValstrFile,ByValreLoad)
'判断reload为 False ,之后检查文件是否加载过
If reload = False and loadedFiles.Exists (strFile) then
ExecuteFileGlobal = False
Exit Function
End if
'加载库函数文件
ExecuteFilestrFile
'将文件加入字典列表
loadedFiles (strFile) = True
ExecuteFileGlobal = True
End Function
|
通过一个例子可以更好理解上面代码。首先我们创建一个要动态加载的库函数文件。
'C:\TestA.vbs
Dim X
X = 2
|
以下代码演示ExecuteFileGlobal的使用方法
'在全局区域加载testa.vbs
ExecuteFileGlobal "C:\testa.vbs", False
Msgbox X '显示 2
X = X + 2
'在全局区域加载testa.vbs,如果已经加载则忽略
ExecuteFileGlobal "C:\testa.vbs", False
Msgbox X '显示4
''在全局区域重新加载testa.vbs
ExecuteFileGlobal "C:\testa.vbs", True
Msgbox X '显示 2
|
问题 9-1. 如何动态定义全局变量
有时我们需要动态在两个或多个Action中共享变量值。使用加载库函数文件的相同概念,我们可以在运行时创建全局变量。
Declare.vbs
'C: \Declare.vbs
Sub ExecuteGlobalCode (sStatement)
ExecuteGlobalsStatement
End Sub
Action1:
'在全局范围执行代码
ExecuteGlobalCode "Dim strText"
strText = "TarunLalwani"
Action2:
'将显示"TarunLalwani"
MsgBoxstrText
|
理解执行作用域
理解测试脚本中全局作用域和本地作用域的区别是很重要的。
1)全局作用域是QTP加载所有测试资源和场景恢复库所在。测试脚本中的所有Action都可以访问
2)本地作用域是指所有在Action中定义的作用区域,不可被此Action之外所访问
图9-2描述了包含两个Action的QTP脚本的作用域视图,来表述QTP如何工作。
1)当脚本启动时QTP创建全局作用域
2)QTP首先添加所有场景恢复库。按照关联顺序从上到下
3)场景恢复库之后,QTP加载所有关联在 Test->Settings…->Resource
(标签)下的文件。加载的顺序是从下到上
4)之后QTP根据测试定义的工作流程按顺序调用每个Action。针对每个Action,QTP创建一个私有的本地作用域。此作用域在每个Action周期建立和释放
5)在Action1中定义的方法不会被其他Action或者全局作用域访问到
图9-2 QTP运行作用域:本地和全局作用域
小提示:如果多个全局库中有同名方法,那么最后一个加载的那个库中的方法会被调用。
Option Explicit的适用性
在库函数文件头部的"Option Explicit"声明允许程序员对所有使用的变量做强制变量声明。但我们可以看到即便在某些关联的库中有"Option
Explicit"声明,对于没有声明的变量也没有抛出错误。
这个出现的原因是源于全局作用域建立的机制。我们需要在所有全局作用域中而不能只在个别全局库函数文件中使用"Option
Explicit"。强制变量声明"Option Explicit"需要放在所有使用的库函数文件中,如果有遗漏,QTP就不会在全局域强制使用变量声明。
全局作用域内执行本地作用域代码
我们之前看过如何在本地作用域加载库函数文件("运行时动态加载本地库函数文件")以及如何从本地加载全局作用域库函数文件("运行时动态加载全局库函数文件")。
有时为了维护脚本我们可能需要在Action之前或之后增加代码。这种维护可能涉及多个数量的脚本。而QTP只允许一次打开一个脚本,所以编辑多个脚本是相当费时的工作。为了避免这种情形我们可以在所有Action中调用两个特殊的方法,代码如下:
'反射任何需要在Action之前执行的代码为语句并执行
Execute GetActionStart()
'Action相关的代码
'执行任何需要在Action之后执行的代码
Execute GetActionEnd()
|
GetActionStart和GetActionEnd方法返回空值或者是需要执行的一段代码。下面是这两个方法的实现。
'每个Action之前调用的方法
'这个方法允许在Action的本地作用域动态执行代码,需要按以下格式在Action开始时调用
'执行GetActionStart()
Function GetActionStart()
'缺省没有执行代码
GetActionStart = ""
'获取需要调用这个方法的Action名字
sAction = LCase(Environment("ActionName"))
If InStr(sAction,"main") Then
GetActionStart = "ExecuteFilePathFinder.Locate(""Workaround.vbs"")"
End If
End Function
'每个Action最后调用的方法
'这个方法允许在Action的本地作用域动态执行代码,需要按以下格式在Action结束时调用
'执行GetActionEnd()
Function GetActionEnd()
'缺省没有执行代码
GetActionEnd = ""
''获取需要调用这个方法的Action名
sAction = Environment("ActionName")
''获取需要调用这个方法的Action名
sAction = LCase(Environment("ActionName"))
。。。
If InStr(sAction,"main") Then
GetActionEnd = "ExecuteFilePathFinder.Locate(""Workaround.vbs"")"
End If
。。。
End Function
|
微软Windows应用编程接口(API)为开发Windows应用程序提供了很多构建好的模块。它提供各种操作方法,比如获取鼠标坐标,窗口句柄,颜色等。QTP支持调用动态链接库内定义的这些方法,但是由于VBScript的限制,只有有限的一部分API可以在QTP中使用。
本章使用的API的更多细节和信息可以从MSDN或者Visual Studio的API
Viewer工具查询获得。
Extern对象
QTP提供一个Extern功能对象用来声明和调用API。
语法
Extern.Declare (RetType, MethodName, LibName, Alias [, ArgType(s)])
|
更多细节可参考QTP用户手册。
VB API定义语法
Private Declare Function GetForegroundWindow Lib "user32.dll" () As Long |
对以上API,我们需要使用QTP的Declare方法确定使用的合适参数:
1、RetType = micLong(函数返回类型)
2、MethodName = "GetForegroudWindow"
(我们可以使用任何其他名字,但是比较好的做法是使用实际API的名字)
3、LibName = "user32.dll" (如果不是使用Windows系统自带的DLL,那么文件名必须使用绝对路径,例如"C:\MyApp\Lib\mylib.dll")
4、Alias = "" 或者"GetForegroudWindow"(如果MethodName跟Alias相同,则Alias可以为空值。
5、ArgType(s) = 本例中不需要传入参数)。
QTP API定义
Extern.Declare micLong,"GetForegroundWindow","user32.dll","GetForegroundWindow" |
以下用一些用例来演示使用API解决通常遇到的问题。
问题 17-1.如何判断当前桌面最上面的为浏览器窗口
'声明GetForeGroundWindow API
extern.Declare micLong,"GetForegroundWindow","user32.dll","GetForegroundWindow"
'获取最前面窗口的句柄
hwnd = extern.GetForegroundWindow()
'判断是否有包含此句柄的浏览器窗口
isBrowser = Browser("hwnd:=" &hwnd).Exist()
If isBrowser then
Msgbox "The top most window is a browser"
End if |
问题 17-2.如何获得Windows的环境变量 (注意不是QTP环境变量)
'变量声明
Dim s_EnvValue
'声明 API "GetEnvironmentVariable"
Extern.Declare micLong,"GetEnvironmentVariable","kernel32.dll","GetEnvironmentVariableA", _
micString,micString+micByRef,micLong
'获取全局变量 "TEMP" 值
Extern.GetEnvironmentVariable "TEMP",s_EnvValue,255 '会得到临时目录路径
MsgBoxs_EnvValue |
问题 17-3.如何使用Windwos API选中Listbox里的选项(item)
' 声明API
Extern.Declare micLong,"SendMessage","user32.dll","SendMessageA",micLong,micLong,micLong,micLong
' 设置Listbox选项item的消息
Const LB_SETSEL = &H185
'方法:根据index选中复选框
Function CheckListBox(hwnd, index)
extern.SendMessagehwnd, LB_SETSEL, True, index
end function
'方法:根据index取消选中复选框
Function UnCheckListBox(hwnd, index)
extern.SendMessagehwnd, LB_SETSEL, False, index
end function |
问题 17-4.如何取到一个文本框的背景色 (当验证必填项跟可选项底色不同时可用到)
'声明需要的 API
Extern.Declare micLong,"GetPixel","gdi32","GetPixel",micLong,micLong,micLong
Extern.Declare micLong,"GetWindowDC","user32","GetWindowDC",micLong
Extern.Declare micLong,"ReleaseDC","user32","ReleaseDC",micLong,micLong
Extern.Declare micLong,"GetDC","user32","GetDC",micLong
Extern.Declare micLong,"SetForegroundWindow","user32","SetForegroundWindow",micLong
Dim hDCSource
Dim hWndSource
Dim backColor
'取得控件的句柄
hWndSource = Window("Window").WinEdit("MandatoryField1").GetROProperty("hwnd")
'将窗口置于最上面,因为GetPixel方法只能针对可见像素使用
extern.SetForegroundWindowhWndSource
'取得设备上下文句柄
hDCSource = Clng(Extern.GetDC(hWndSource))
'取得相关控件的像素(1,1)点的背景色
backColor = Clng(Extern.GetPixel(hDCSource, Clng(1),Clng(1)))
MsgBoxbackColor
'释放设备上下文句柄
Extern.ReleaseDChWndSource, hDCSource |
问题 17-5.如何使用Windows API模拟键盘操作
'声明API:键盘事件keybd_event
extern.Declare micVoid,"keybd_event","user32" ,"keybd_event", _
micbyte,micbyte,miclong,miclon
'声明API:虚拟按键码映射MapVirtualKey
extern.Declare micLong,"MapVirtualKey","user32","MapVirtualKeyA", _
micLong, micLong
Const KEYEVENTF_EXTENDEDKEY = &H1
Const KEYEVENTF_KEYUP = &H2
Const KEYEVENTF_KEYDOWN = &H0
Sub KeyDown(KeyAscii)
keyCode = extern.MapVirtualKey(KeyAscii, 0)
'触发按键按下事件
extern.keybd_eventKeyAscii, keyCode, KEYEVENTF_KEYDOWN, 0
End Sub
Sub KeyUp(KeyAscii)
keyCode = extern.MapVirtualKey(KeyAscii, 0)
'触发按键抬起事件
extern.keybd_eventKeyAscii, keyCode, KEYEVENTF_KEYUP, 0
End Sub
Sub KeyPress(KeyAscii)
KeyDownKeyAscii
KeyUpKeyAscii
End Sub |
对“计算器”使用以上代码
'声明键值常量
Const vbKey1 = 49
Const vbKey2 = 50
ConstvbKeyAdd = 107
ConstvbKeyReturn = 13
SystemUtil.Run"calc.exe"
Window("title:=Calculator").Activate
Call KeyPress(vbKey1)
Call KeyPress(vbKeyAdd)
Call KeyPress(vbKey2)
Call KeyPress(vbKeyReturn)
|
使用以上代码模拟CTRL+ALT+S
'声明键值常量
ConstvbKeyControl = 17
ConstvbKeyAlt = 18
ConstvbKeyS = 83
Call KeyDown(vbKeyControl)
Call KeyDown(vbKeyAlt)
Call KeyDown(vbKeyS)
Call KeyUp(vbKeyS)
Call KeyUp(vbKeyAlt)
Call KeyUp(vbKeyControl) |
问题 17-6.如何防止电脑因为屏保而锁住
有时我们需要执行耗时很长的无人值守脚本,如果几分钟没有键盘或鼠标操作,屏保策略会使机器锁住,将导致QTP脚本不能执行的问题。我们可以使用以下键盘和鼠标模拟事件来避免这种情况。
'C:\PreventPCLock.vbs
ConstmicVoid = 0
ConstmicByte = 26
ConstmicLong = 3
Const KEYEVENTF_KEYUP = &H2
'创建Extern对象
Set Extern = CreateObject("Mercury.ExternObj")
extern.Declare micVoid,"keybd_event","user32" ,"keybd_event" , _
micByte,micbyte,miclong,micLong
Extern.Declare micVoid,"Sleep","kernel32","Sleep",micLong
While True
extern.keybd_event 0, 0, KEYEVENTF_KEYDOWN, 0
Extern.Sleep 20000
Wend |
小提示:以上代码有可能会产生“无法找到指定模块”的错误,这是因为包含这些类的DLL在注册表中并未包含完整路径造成的。为了解决这个问题,需要将QTP安装后的bin文件夹添加到Windows的PATH环境变量中。
我们可以使用如下代码将QTP的bin目录加到windows的PATH环境变量中
'此函数将一个目录加入到PATH环境变量
Public Function AddToSystemPath(ByVal Path)
Set objWMIService = GetObject("winmgmts:\\.\root\cimv2")
'取得Windows环境变量
Set colItems = objWMIService.ExecQuery _
("Select * From Win32_Environment Where Name = 'Path'")
For Each objItem in colItems
'如果PATH中还没有此路径,将它添加到PATH变量中
If InStr(objItem.VariableValue, Path)= 0 Then
'如果路径不存在则添加
strPath = objItem.VariableValue& ";" & Path
objItem.VariableValue = strPath
objItem.Put_
End If
Next
End Function
AddToSystemPath "C:\Program Files\Mercury Interactive\QuickTest Professional\bin" |
传入一个键码值(keyascii)为0到keyba_event方法中会触发一个没有按键的键盘事件。以上代码可以以放在VBScript文件中运行。
问题 17-7.如何最大化一个窗口或浏览器
'声明
Private Const SW_MAXIMIZE = 3
Extern.DeclaremicLong, "ShowWindow", "user32.dll", "ShowWindow", _
micHwnd, micLong
'如果要最大化一个窗口,那需要使用它的句柄.
hWndWindow = Browser("creationtime:=0").GetROProperty("hwnd")
'最大化窗口
Extern.ShowWindowhWndWindow, SW_MAXIMIZE
|
问题 17-8.如何从一个URL下载文件到本地硬盘
'Declare Function URLDownloadToFile Lib "urlmon" Alias "URLDownloadToFileA"
'( ByValpCaller As Long, ByValszURL As String, ByValszFileName As String,
'ByValdwReserved As Long, ByVallpfnCB As Long ) As Long
Extern.DeclaremicLong,"URLDownloadToFile","urlmon","URLDownloadToFileA", _
micLong,micString,micString,micLong,micLong
sSourceURL = http://mysite/logo.gif
sTargetFile = "C:\logo.gif"
Extern.URLDownloadToFile 0, sSourceURL, sTargetFile, 0,0 |
第二十八章 QTP高级应用
在本章我们将会讨论QTP中各种相对高级的常见问题及解决方案,这里故意把本章留在最后,主要的原因是本章的各种概念在之前的很多章节中已经提到过,我们还会介绍Settings对象在运行时遍历所有的子项,此技术可以用于研究发现QTP的一些文档未公开的隐藏特性。
不同机器的测试脚本同步执行
在一些复杂的测试系统场景下会需要QTP去通过脚本去触发另一个脚本以及需要执行的被测应用,在这类情况下,我们需要通过同步通知方式来使不同种类的应用进行协同工作。
为了解决此类问题,我们需要从QTP脚本运行中获取到过程信息,主要是通过QTP的自动化模型AOM下的Environment对象接口来实现所需要的同步进行协作和控制的脚本执行。以下脚本展示了怎样通过自动化模型AOM获取到本地机和远程机上的环境变量Environment对象:
'获取正在运行QTP的对象引用
Set qtpLocalPC = CreateObject("QuickTest.Application")
sRemoteIP = "10.1.1.1"
Set qtpRemotePC = CreateObject("QuickTest.Application", sRemoteIP)
'获取到环境变量
Set qtpLocalEnv = qtpLocalPC.Test.Environment
Set qtpRemoteEnv = qtpRemotePC.Test.Environment
'最终可以访问到环境变量
MsgBox qtpLocalEnv("TestDir")
MsgBox qtpRemoteEnv("TestDir")
|
那么现在就需要等待QTP运行合适的位置时对指定环境变量进行更新,看一下如下QTP脚本:
QTP脚本1
'脚本1Script 1
'创建同步点环境变量
Environment.Value("SyncPoint1") = False
Msgbox "Job 1 Completed"
'实现任意操作
'<-- 另一个脚本会等待此同步点为True
Environment.Value("SyncPoint1") = True
Msgbox "Starting Job 2"
|
此Vbscript脚本会等待QTP脚本1更新SyncPoint1的状态后才开始执行:
'本地机器IP
strCompIP = "127.0.0.1"
Set qtpApp = CreateObject("QuickTest.Application", strCompIP)
'等待脚本停止
While Not qtpApp.Test.IsRunning
Wend
'等待同步点SyncPoint环境变量更新为True
While qtpApp.Test.Environment("SyncPoint1") <> True Wend
MsgBox "Script 1 has passed the sync point."
|
在QTP中运行脚本1以及脚本2,脚本2将会等待Job 1 Competed消息后弹出Script1
has passed the sync point消息框。
利用脚本停止脚本并重新运行脚本
这里列举一些常见的需要重新停止并重新运行脚本的情况:
1、当动态加载环境变量后必须停止并重新运行才能被正确加载到测试脚本中
2、当在测试TE过程中需要运行多个Session,QTP不允许在单次脚本运行中运行多个TE
Session,若需在脚本中运行多个Session,那么就需要在每个Session最后停止并从下一个session点继续执行。
此技术通常用于重启QTP并且只对第一次运行有效,当在不需要执行脚本并需要重新运行时停止QTP,通过运行一个异步脚本来控制当QTP一旦进入到非运行模式下就运行它直到脚本结束。
'停止并重运行QTP
Sub StopAndReRunQTP(restartFlag)
'只在flag没有被使用过时重启
If Setting.Exists(restartFlag) = False then
'一旦flag不存在则保留flag在整个QTP Session中
Setting.AddrestartFlag,True
'调用异步脚本当QTP停止后控制其继续执行
Call AsyncReRunQTP
'测试结果中关闭所有事件
Reporter.Filter = rfDisableAll
'当出现错误时立即停止脚本
Setting("OnReplayError") = "Stop"
'出现错误停止测试r
Err.RaisevbObjectError+ 1,"Stop", "Causing Error for Stopping QTP"
End if
End Sub
Sub AsyncReRunQTP()
'运行时创建重运行脚本
Call CreateQTPRunScript()
'运行异步脚本
Set wShell = CreateObject("WScript.Shell")
wShell.Run"ReRunQTP.vbs"
End Sub
Public Function CreateQTPRunScript()
'创建脚本等待qtp停止并重新运行
Set fso = CreateObject("Scripting.FileSystemObject")
setfile = fso.OpenTextFile("ReRunQTP.vbs",2, True)
file.WriteLine"Set qtpApp = CreateObject(""QuickTest.Application"")"
file.WriteLine"While qtpApp.Test.IsRunning"
file.WriteLine"Wend"
file.WriteLine"qtpApp.Test.Run ,False"
file.close
setfile = nothing
setfso = nothing
End Function
|
StopAndReRunQTP函数会检查flag是否存在于Setting中,如果不存在则停止QTP,此处Setting设置持续周期起到了关键作用,如果没有它则无法完成以上所实现的功能。
AsyncReRunQTP函数创建并执行了一个VBScript脚本,而此脚本会在运行时重新运行QTP,重运行脚本如下:
'创建QTP应用对象
Set qtpApp = CreateObject("QuickTest.Application")
'等待测试停止
While qtpApp.Test.IsRunning
Wend
'运行测试
qtpApp.Test.Run ,False
|
|