使用 RFT 設計 Web 2.0 應用的 GUI 自動化測試框架

myattitude發表於2010-03-04

轉自:http://www.ibm.com/developerworks/cn/rational/r-cn-webtopguitestframework/index.html

近些年來,隨著 Web 2.0 技術的大範圍普及和廣泛應用,在全球範圍內出現了眾多新穎的激動人心的軟體產品或服務。在這些 Web 應用中,有一類主要的分支被稱作 Web 桌面應用。Rational Functional Tester(RFT)是 IBM 提供的一款自動化測試工具,適用於各種測試工作,特別擅長於 GUI 方面的自動化測試。

本文藉助在 Rational Functional Tester(RFT)平臺下設計和開發 LotusLive Meeting 這個自動化測試專案,介紹瞭如何使用 Rational Functional Tester 設計 Web 2.0 應用的 GUI 自動化測試框架,並介紹自動化測試框架設計和開發中的一些原則和經驗。

前言

近些年來,隨著 Web 2.0 技術的大範圍普及和廣泛應用,在全球範圍內出現了眾多新穎的激動人心的軟體產品或服務。在這些 Web 應用中,有一類主要的分支被稱作 Web 桌面應用。例如,widgetop、cloudworks、eyeOS、Mygoya、Wixi 等。在 IBM 公司內部很多產品線也開始逐步開發出或者轉移到 Web 平臺。在 IBM 軟體產品和服務中,具有 Web 桌面應用特點的產品也非常的多,像是 Domino iNotes,LotusLive Meeting,Sametime Meeting 等。作為 GUI 自動化軟體測試人員或者框架及指令碼開發人員,如何找到一種高效、穩定的並且是針對這種軟體架構和產品特性的 GUI 自動化測試方法就顯得尤為重要了。

Rational Functional Tester(RFT)是 IBM 提供的一款自動化測試工具,適用於各種測試工作,特別擅長於 GUI 方面的自動化測試。在 IBM 公司內部的各個測試組,例如 FVT、BVT、GVT,甚至是 SVT 都得到了廣泛的應用。

本文藉助在 RFT 平臺下設計和開發 LotusLive Meeting 這個自動化測試專案,來介紹一下自動化測試框架設計和開發中的一些原則和經驗。

Web 桌面應用及特點

隨著 Web 開發技術的日新月異,很多 Web 應用都開始越來越注重使用者的體驗。其中 Web 桌面應用(Webtop)在很大程度上滿足了使用者日常使用桌面應用的習慣,在眾多的新穎的 Web 應用中佔有較大的比例。具有 Webtop 特點的 Web 應用一般具有以下的特點:首先從使用者的角度,如果我們沒發覺它是執行的瀏覽器裡面,那麼它的使用者體驗更像是傳統桌面程式。也就是說在使用過程中不像是其他 Web 應用要在相對較多的瀏覽器視窗之間或者頁面之間進行跳轉,而是一直維持著一個相同的瀏覽器視窗。UI 的變化都發生在同一個瀏覽器視窗物件內部。另外從技術角度上講,瀏覽器視窗內的頂層 DOM 物件基本保持不變,很多 UI 的變化都是重新整理或動態載入區域性容器的來實現的。對於這類應用的特點,在做自動化測試指令碼開發過程中可以加以利用,大大提高指令碼的質量和執行效率。

ITCL 框架

ITCL 框架是 IBM 公司內部被廣泛使用的自動化設計框架,也叫做 IBM 框架。主要的設計宗旨就是將程式碼劃分成三層結構,即物件層(Objects layer)、任務層(Task layer)、測試用例層(Testcase layer)。將程式碼劃分成三層結構使得“做什麼“和”如何做“分離開來,有利於程式碼的組織,結構清晰。同時提高了程式碼的可複用性和擴充套件性。當使用 ITCL 框架開發自動化測試指令碼時,最核心的任務就是合理的設計和組織物件層和任務層。合理的設計物件層和任務層常常會使整個自動化專案的開發和後期維護達到事半功倍的效果。本文的主要目的就是提供一套設計原則以及一些物件是別的經驗,針對 Web 桌面應用程式的特點給出物件層設計的解決方案。以提到物件識別的準確性和穩定性,這一點對於 UI 經常變化的軟體和 NVL 版本軟體的國際化測試有特別重要的意義。

LotusLive Meeting 的框架設計原則

LotusLive Meeting 是一個典型的 Web 桌面應用程式,對於這型別的應用,最大的特點就是很多 RFT 可識別的物件是以樹形結構組織並且結構較為固定。同時這些物件是在同一個瀏覽器視窗內被展現。針對於這樣的特點我們可以借鑑樹形結構搜尋物件的一些基本方法,即從樹根開始逐級遍歷樹的各個節點進行匹配,直到找到我們要操作的 GUI 物件。那麼構成這棵樹的節點是什麼呢?這裡我們就要說面一個 HTML 容器物件的概念。

HTML 容器物件

Web 應用說到底是基於 Web 技術,是基於瀏覽器的。那麼不管目前主流的 Web 應用是以何種技術開發,使用的是何種平臺,他們都依賴於最基本的 HTML 語言。我們可以發現,HTML 的作用主要是佈局 Web 應用的展示層。也就是說 Web 應用的 GUI 佈局主要是通過 HTML 的各種標記例如 等來實現的。這些標記劃分出的各個區域就像是一個個小的容器,容納了其他的 GUI 物件。而且這些標記可被 RFT 的物件識別機制識別,對應成相應的 HTML 容器物件。另外還有一個可被 RFT 識別的主要物件,就是 DOM 物件。在 RFT 的物件識別機制中,它是瀏覽器物件下的第一個容器物件同樣對 GUI 元素的識別有重要作用。前面提到的物件樹就是由這些容器物件構成的。如下圖所示:


圖 1. HTML 容器物件架構
圖 1. HTML 容器物件架構

檢視圖 1 大圖

從上圖我們可以看出,容器物件的包含關係是有一定的規則的。也就是說 HTML DOM 是瀏覽器物件下的第一個物件,承載整個頁面的內容。THML DOM 物件之下可以是 Frameset 物件、Frame. 物件、Form. 物件、或者是 GUI 物件。Frameset 物件之下只能是 Frame. 物件,Frame. 物件之下又可以是 HTML DOM 物件或者 Form. 物件。這樣由 HTML 容器物件便可以組成容器物件樹。而被操作的 GUI 物件元素就是這棵樹的葉子節點。從根物件出發找到某個 GUI 物件的過程就是沿著這棵樹的某個分支搜尋 GUI 物件的過程。如下圖:


圖 2. 容器物件查詢
圖 2. 容器物件查詢

從圖中我們可以看到,從 A 物件開始找到 D 物件的過程經過了 B 和 C 物件。如果 D 物件就是我們要操作的 GUI 物件,那麼它上層的物件就是包含它的容器物件。從前面的介紹中我們知道,容器物件在應用中是不可見的。也就是說他們都是些 HTML 標記,在滿足 HTML 語法規則的情況下相互巢狀,構成了整個頁面的佈局。按照 ITCL 框架的規則,在物件層我們要定義 A、B、C 三個容器物件,同時實現 geter 方法。A 物件首先定位到 B 物件,然後 B 物件搜尋得到 C 物件。這樣逐級搜尋得到物件便於物件層的擴充套件。如果產品修改了 UI 的設計使得 A 物件下面多出了 B' 物件,那麼只要在 A 物件內重新實現 B' 物件的 getter 方法。

LotusLive Meeting 容器物件架構

以 lotusLive Meeting 為例,藉助於 RFT 的物件檢視器(Object Inspector)我們繪製出了容器物件的基本架構。如下圖:


圖 3. LoutsLive Meeting 容器物件架構
圖 3. LoutsLive Meeting 容器物件架構

檢視圖 3 大圖

從圖中我們可以看到,由 HTML 容器節點構成的樹將應用的整個頁面進行了劃分。被操作的 GUI 物件都是樹的葉子節點。從圖中我們可以看到如果我們想找到並操作位於 ToolbarDOM 物件下的一個 button 物件的話,那麼我們要做的就是通過這樣一條路徑: Root->ConsolDOM->MainFrameSet->ConfwinFrame->ConferenceWindowDOM->VframeSet->ToolbarFrame->ToolbarDOM->Buttom object 。在具體的實現過程中,上圖中的所有容器物件都將被定義成一個類。這些類有一個共同的基類那就是 RFT 提供的 TestObject 類。通過對這些容器類的例項化物件呼叫 RFT 的方法,也就是我們常使用的動態查詢物件的方式,即物件的 find() 方法來逐級的找到要操作的 GUI 物件元素。ConsolDOM 類的程式碼示意如下:


清單 1. ConsolDOM 類的程式碼

public class ConsolDOM extends HtmlDocument
{
public ConsolDOM(TestObject arg0) {
super(arg0);
}
public ConsolDOM(TestObjectReference arg0) {
super(arg0);
}
ObjectGetter g = new ObjectGetter();
public MainFrameSet getMainFrameSet()
{
try {return new MainFrameSet(og.getObject(this, Webfuncs.gsClassProp
 , Webfuncs.umHFraSetRef, Webfuncs.gsIDProp, "main"));}
 catch(Exception e){return null;}
}
} 

從程式碼中我們看到,除了構造方法 ConsolDOM 類只實現了一個 Getter 方法 getMainFrameSet(),因為它的下層只有這一個容器物件。MainFrameSet 類的實現程式碼如下:


清單 2. MainFrameSet 類的實現程式碼

public class MainFrameSet extends HtmlFrameSet
{
public MainFrameSet(TestObject arg0) {
super(arg0);
}
public MainFrameSet(TestObjectReference arg0) {
super(arg0);
}
ObjectGetter g = new ObjectGetter();
public ConfwinFrame. getConfwinFrame()
{
try{return new ConfwinFrame(og.getObject(this, Webfuncs.gsClassProp
 , Webfuncs.umHtmlFrameRef, Webfuncs.gsIDProp, "confwin"));}
 catch(Exception e){return null;}
}
}

ConferenceWindowDOM 類的實現程式碼如下:


清單 3. ConferenceWindowDOM 類的實現程式碼

public class ConferenceWindowDOM extends HtmlDocument
{
public ConferenceWindowDOM(TestObject arg0) {
super(arg0);
}
public ConferenceWindowDOM(TestObjectReference arg0) {
super(arg0);

}
ObjectGetter g = new ObjectGetter();
public VframeSet getVFrameSet()
{
try{return new VframeSet(og.getObject(this, Webfuncs.gsClassProp
 , Webfuncs.umHFraSetRef, Webfuncs.gsIDProp, "vframeset"));}
 catch(Exception e){return null;}
}
} 

VframeSet 類的實現程式碼:


清單 4. VframeSet 類的實現程式碼

public class VframeSet extends HtmlFrameSet
{
public VframeSet(TestObject arg0) {
super(arg0);
}
public VframeSet(TestObjectReference arg0) {
super(arg0);
}
ObjectGetter g = new ObjectGetter();
public ToolbarFrame. getToolbarFrame()
{
try{return new ToolbarFrame(og.getObject(this, Webfuncs.gsClassProp
 , Webfuncs.umHtmlFrameRef, Webfuncs.gsIDProp, "toolbar"));}
 catch(Exception e){return null;}
}
public HframeSet gethFrameSet()
{
try{return new HframeSet(og.getObject(this, Webfuncs.gsClassProp
 , Webfuncs.umHFraSetRef, Webfuncs.gsIDProp, "hframeset"));}
 catch(Exception e){return null;}
}
public StatusFrame. getStatusFrame()
{
try{return new StatusFrame(og.getObject(this, Webfuncs.gsClassProp
 , Webfuncs.umHtmlFrameRef, Webfuncs.gsIDProp, "status"));}
 catch(Exception e){return null;}
}

}

從 lotuslive Meeting 容器架構圖中我們看到,VframeSet 容器下有三個 THML 容器 ToolbarFrame、 HframeSet、 StatusFrame。所以要實現著三個容器的 Getter 方法。類似的 ToolbarFrame. 要實現一個 ToolbarDOM 的 Getter 方法,最終得到 ToolbarDOM 物件。以查詢 ToolbarDOM 下的一個 button 為例,示例程式碼如下:


清單 5. 任務層中通過 Root 物件找到 consolDom 物件

TestObject[] to=root.find(atDescendant(Webfuncs.gsClassProp,Webfuncs.gsDocumentRef,
Webfuncs.gsTitleProp,VisualReporter.gsUMDomTitle));
if(to.length>1)
{
for(int i=0;i

在任務層中由 consolDom 物件得到 VframeSet, 再通過 VframeSet 找到 ToolbarDOM:


清單 6. 任務層程式碼示例

MainFrameSet mainFrameSet=consolDom.getMainFrameSet();
ConfwinFrame. confirwinFrame=mainFrameSet.getConfwinFrame(); 
ConferenceWindowDOM conWinDom=confirwinFrame.getConferenceWindowDom();
VframeSet vframeSet=conWinDom.getVFrameSet();
ToolbarFrame. toolBarFrame=vFrameSet.getToolbarFrame();
ToolbarDOM toolBarDom=toolBarFrame.gettoolbarDom(); 

從上面的程式碼可以看到,各個物件類都實現了 Get 方法來獲取下一級被包含的物件,這樣做有幾個好處:

  • 對於物件層的類來說的查詢的範圍使得查詢更為精確。很大程度避免了同一組查詢屬性篩選出了多個物件的情況。
  • 避免了每次查詢對由於各個物件逐,結構清晰,便於維護。
  • 物件的查詢時逐級進行的,縮小級的呼叫 find 方法象都從 Root 物件開始查詢,提高了查詢執行的效率。

    使用 RFT 來探測物件屬性

    即使是使用 RFT 的 API 來動態查詢物件,查詢也是基於某些物件的識別屬性進行的。所以要先通過 RFT 來探測物件的可識別屬性。利用 RFT 提供的一個 Tool—物件識別器(Object Inspector)可以方便的檢視物件屬性。如下圖:


    圖 4. 物件識別器示例
    圖 4. 物件識別器示例

    檢視圖 4 大圖

    這裡我們選擇物件的識別屬性的時候有些技巧。我們一般優先選擇實現層的屬性,儘量避免選擇 UI 展示層的屬性。例如我們會選擇 .id.classIndex.classtype.name.title 等屬性,而儘量不選擇 UI 上面的 String 或者是物件的 .text 屬性。因為這些 UI 展示層的屬性經常會隨著產品的版本更替而頻繁的發生改變,對自動化指令碼的維護帶來很大不便。特別是在 GVT 的自動化測試中,經常有需求一套自動化指令碼要跑在不同語言的 build 上面。這就需要指令碼不依賴於或者儘量少依賴於 UI 的展示層屬性,而是在實現層篩選屬性來識別物件。這樣可以做到一套指令碼在不同的語言 UI 上執行,並且實現層的屬性較為穩定,在產品進行小版本的升級過程中變化不大,大大的降低的程式碼的維護成本。另外,當我們使用實現層的屬性來查詢物件的時候,如果每次都從 Root 物件來查詢的話,經常會遇到帥選出多個物件的情況。因為實現層的屬性唯一性不夠,所以經常查到多個符合要求的物件,例如 OK 按鈕之類的物件。這樣對精確定位物件帶來了麻煩。但是,採用了前面提到的樹狀結構組織物件,進行自頂向下的逐級查詢,這樣就可以逐步的縮小查詢的範圍,做到相對精確的定位 GUI 物件了。

    總結

    從上文可以看出,利用樹狀結構來組織 HTML 容器物件,從而劃分 GUI 元素的方式可以大大的提高物件層的穩定性。同時降低物件識別屬性和 UI 展示層的耦合度,可以方便的使用實現層的屬性來識別物件。自頂向下的逐步縮小查詢範圍可以更精確的定位 GUI 元素的位置。結合 ITCL 框架的使用可以很大程度提高指令碼的適應性,穩定性。使自動化指令碼的開發適應敏捷(Agile)模式的產品開發特性,以及 FVT、BVT、甚至是 GVT 測試中不斷變化的 GUI 設計和實現,降低了指令碼後期維護的代價。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/14780914/viewspace-628573/,如需轉載,請註明出處,否則將追究法律責任。

相關文章