第一章 簡介
什么是自動化測試
自動化測試是對一個已有的手工測試過程減少并盡可能排除人工干預的過程。
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用來關聯的對象。
理解這兩種對象類型的區別是非常重要的??梢钥闯蓛奢v車;車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
|
|