国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > .NET > 正文

用 .NET 開發的輕量級 UI 測試自動化

2024-07-10 12:58:39
字體:
來源:轉載
供稿:網友

james mccaffrey

下載本文的代碼: testrun0501.exe (131kb)



本頁內容
待測試應用程序
測試自動化腳本
操作待測試應用程序
檢查應用程序狀態
討論

手動用戶界面測試是一種最基本的軟件測試類型,大多數軟件工程師首次采用的就是這種測試類型。與此矛盾的是,自動化用戶界面測試可能是編寫的測試類型中最具技術挑戰的一種。microsoft® .net 環境為您提供了許多編寫自動用戶界面測試自動化的方式。一種常見而有用的方法是記錄擊鍵、鼠標移動和單擊,然后在應用程序中回放以確保它以預期方式執行。(有關這種方法的詳細信息,請參見 msdn®magazine 2002 年 3 月號中 john robbins 的 bugslayer 專欄。這一期 msdn magazine 的 paul dilascia 專欄也闡釋了如何使用 .net 將這種類型的輸入發送到另一個應用程序中。)在本月的專欄中,我將探討為 .net 應用程序編寫輕量級 ui 測試自動化的另一種方法。

最好的方式是以一個屏幕快照開始進行討論。圖 1 顯示我有一個虛擬應用程序要進行測試。它是一個顏色合成器應用程序,允許用戶在文本框控件中鍵入一種顏色,然后在 combobox 中鍵入或選擇一種顏色,單擊按鈕,listbox 就會顯示一條消息,表明兩種顏色“混合”的結果。在圖 1 中,根據應用程序,紅色和藍色會產生紫色。ui 測試自動化是一個控制臺應用程序,它啟動一個待測試窗體,模擬用戶移動應用程序窗體,定義和調整應用程序窗體的大小,設置文本框和 combobox 控件的值,并單擊按鈕控件。測試自動化檢查測試應用程序的結果狀態,驗證 listbox 控件包含正確的消息,并記錄“pass”結果。圖 1 中的屏幕快照是在測試自動化模擬用戶單擊關閉測試應用程序的 file | exit 之前捕獲的。



圖 1 窗體 ui 測試自動化


在下面的章節中,我將簡要介紹我所測試的虛擬應用程序,解釋如何使用反射和 system.windows.forms.application 類啟動測試自動化程序中的應用程序窗體,介紹如何使用 system.reflection 命名空間中的方法模擬用戶操作和檢查應用程序狀態,并描述如何擴展和修改測試系統來滿足自己的需要。我想,不管您在軟件生產環境中扮演什么樣的角色,具備快速編寫輕量級 ui 測試自動化的能力都能使您的技能得到很大提高。另外,即使您正在使用一個已有的框架(如 nunit),這些相同的技術也可以整合到您自己的單元測試管理中并相關。

待測試應用程序


讓我們來看一下待測試應用程序,以便理解測試自動化的目標。待測試顏色合成器應用程序是一個簡單的 windows® 窗體。應用程序的代碼是使用 c# 編寫的,但我將向您介紹的 ui 自動化技術適用于用任何以 .net 為目標的語言編寫的應用程序。我接受 visual studio® .net 默認控件名稱 form1、textbox1、combobox1、button1 和 listbox1。當然,在實際的應用程序中,您應該更改控件的名稱來反映它們的功能。我添加了三個虛擬菜單項:file、edit 和 view。圖 2 中列出的代碼是待測試應用程序的主要內容。

當用戶單擊 button1 控件時,應用程序就會獲取 textbox1 和 combobox1 控件中的值。如果這兩個顏色字符串匹配,就會顯示這種顏色的消息。如果文本框和 combobox 控件分別包含“red”和“blue”,則顯示結果消息“purple”。如果文本框和 combobox 控件中為其他任何顏色組合,則顯示結果消息“black”。因為這只是用于演示的虛擬應用程序,我想讓代碼盡可能簡短,所以沒像在實際應用程序中那樣檢查輸入參數。雖然這個應用程序非常簡單,但它具備了演示自動化 ui 測試所需要的基于 windows 應用程序的大多數基本特征。

即使對于如此小的應用程序,要手動測試它的用戶界面也是很繁瑣、易出錯、耗時且又低效的。您必須鍵入一些輸入,單擊按鈕控件,直觀驗證結果消息,并將結果記錄到 excel 電子表格或其他數據存儲中。因為應用程序接受用戶在文本框控件中的自由輸入,實際上可能的測試輸入是無限的,所以您必須測試上百甚至上千個輸入才能很好地理解應用程序的行為。對于上述所有操作,一旦應用程序代碼有所更改,您就必須從頭執行相同的手動測試。編寫單元測試是一個更好的方法,因為這些測試允許您模擬使用該應用程序的用戶,然后確定應用程序是否正確響應。

返回頁首
測試自動化腳本


圖 3 顯示了測試自動化管理的整體結構,圖 4 顯示了代碼大綱。這里我使用了 c#,但您可以很容易地將代碼修改為任何基于 .net 的語言。



圖 3 ui 測試自動化結構


我首先添加和聲明 system.windows.forms、system.reflection 和 system.threading 命名空間的引用。因為默認情況下控制臺應用程序不引用 system.windows.forms.dll,所以要使用這個命名空間中的類,就需要添加對 system.windows.forms.dll 文件的項目引用。system.windows.forms 命名空間包含 forms 類和 application 類,它們在這個解決方案中都有使用。我使用 system.reflection 中的類來獲取和設置窗體控件的值并調用與該窗體相關的方法。使用 system.threading 中的方法來從控制臺應用程序測試管理啟動窗體。

我聲明了三個類作用范圍對象,因為在測試管理中有幾個方法要用到它們:

static form testform = null;
static bindingflags flags = bindingflags.public |
bindingflags.nonpublic |
bindingflags.static | bindingflags.instance;
static int delay = 1500;

因為顏色合成器應用程序只是一個 windows 窗體,所以我聲明一個 form 對象來表示它。system.reflection 命名空間中有許多方法將 bindingflags 對象作為篩選器使用。我為 thread.sleep 方法設置了一個值為 1500(毫秒)的整型延時變量,這樣在測試自動化的各個時刻都可以暫停 1.5 秒。我使用這段代碼來啟動待測試應用程序:

console.writeline("/nlaunching winapp under test");
string exepath = "c://formuiautomation//winapp//bin//debug//winapp.exe";
testform = launchapp(exepath, "winapp.form1");


我定義了圖 5 中的 launchapp 方法及其 helper 方法 runapp。這段代碼的行數不多,但作用很大。請注意,為了簡單起見,我硬編碼了指向待測試應用程序可執行文件的路徑(在您自己的測試中,您可能想用參數表示這個信息以使得測試自動化更加靈活)。launchapp 方法接受應用程序可執行文件的路徑和應用程序窗體的名稱,并返回一個表示該窗體的對象。launchapp 使用 assembly.loadfrom 靜態方法創建 assembly 對象的實例,而不是通過顯式調用構造函數來創建。

接下來,assembly.gettype 方法返回一個表示應用程序窗體的類型,然后我使用 assembly.createinstance 方法創建對待測試窗體的引用。然后我發起一個新的線程來實際啟動應用程序窗體。application.run 方法開始在當前線程進行消息循環;由于我想在窗體可見時執行工作,所以我需要使 application.run 在自己的線程中運行,這樣循環才不會阻止我的進程。通過使用這種技術,測試自動化控制臺應用程序管理和窗體就會在不同線程但相同的進程下運行。這種方式可以使它們相互通信 — 也就是說,測試管理可以發送指令給 windows 窗體。

返回頁首
操作待測試應用程序


當啟動待測試應用程序后,我模擬用戶操作應用程序窗體。示例測試方案是從移動窗體和調整窗體大小開始的,如下所示:

console.writeline("moving form");
setformpropertyvalue("location", new system.drawing.point(200,200));
setformpropertyvalue("location", new system.drawing.point(500,500));

console.writeline("resizing form");
setformpropertyvalue("size", new system.drawing.size(600,600));
setformpropertyvalue("size", new system.drawing.size(300,320));

setformpropertyvalue 方法執行了所有工作(請參見圖 6)。我使用 object.gettype 方法創建表示應用程序窗體的 type 對象,然后使用該對象獲得引用窗體屬性(例如 location 屬性或 size 屬性)的 propertyinfo 對象。一旦擁有屬性信息對象,就可以使用 propertyinfo.setproperty 方法來操作它。setproperty 接受三個參數。前兩個可能是您想要的 — 對包含要更改屬性的對象的引用和對新屬性值的引用。

第三個參數是必需的,因為有些屬性(例如 listbox 控件的 items 屬性)是索引的。我這里所做的移動窗體和改變窗體大小實際上與測試應用程序功能并不相關,但我想通過它告訴您如何實現以防您的測試方案需要。還要注意,我正在使用的是 form 類(實際上是它的 control 基類)公開的 isynchronizeinvoke 接口。您應該只通過擁有控件底層窗口句柄的線程訪問(包含 form)控件的屬性。對于待測試窗體,該線程就是為運行 application.run 而發起的線程。由于我的測試管理是在單獨的線程中運行的,所以我需要將對控件的屬性和方法的訪問封送到該線程,使控件的 invoke 方法和 invokerequired 屬性成為一體(該方法和屬性都是 isynchronizeinvoke 接口的一部分)。有關 isynchronizeinvoke 的更多信息,請參閱 msdn magazine 2003 年 2 月號中 ian griffith 的文章:give your .net-based application a fast and responsive ui with multiple threads。

現在我準備模擬用戶在文本框控件中鍵入一種顏色,并從 combobox 控件選擇一種顏色:

console.writeline("/nsetting textbox1 to 'yellow'");
setcontrolpropertyvalue("textbox1", "text", "yellow");
console.writeline("setting textbox1 to 'red'");
setcontrolpropertyvalue("textbox1", "text", "red");

console.writeline("selecting combobox1 to 'green'");
setcontrolpropertyvalue("combobox1", "selecteditem", "green");
console.writeline("selecting combobox1 to 'blue'");
setcontrolpropertyvalue("combobox1", "selecteditem", "blue");

我先將 textbox1 設置為“yellow”,再將其設置為“red”,然后將 combobox1 設置為“green”,再設置為“blue”。所有的實際工作都是由圖 7 中所示的 setcontrolpropertyvalue 方法完成的。

我使用 thread.sleep 方法來暫停測試自動化以確保待測試應用程序已啟動并運行。創建表示應用程序窗體類型的 type 對象之后,我使用 type.getfield 方法檢索 form 對象中指定字段(控件)的信息。然后調用 fieldinfo.gettype 方法獲得表示想要操作的控件的 type 對象。一旦擁有控件對象,我就可以像操作 form 對象那樣操作該控件對象,即獲取控件的 propertyinfo,然后調用 setvalue 方法。對于 setformpropertyvalue,需要確保所有的屬性更改都是在正確的線程中進行的。

請注意,測試自動化并不直接模擬極低水平的用戶操作。例如,自動化并不模擬對 textbox1 控件的各次擊鍵,而是直接設置 text 屬性。同樣,自動化不模擬對 combobox1 控件的點擊,而是設置 selecteditem 屬性。這是我的測試自動化系統的一個設計缺陷。要采取那種方式測試,您可以按照 john robbins 在前面提到的文章中的建議來做。

模擬用戶在文本框和 combobox 控件中鍵入顏色的操作之后,自動化會模擬點擊按鈕控件:

console.writeline("clicking button1");
invokemethod("button1_click", new object[]{null, eventargs.empty} );

我已經定義了如圖 8 所示的 invokemethod 方法。

invokemethod 通過調用 object.gettype 方法獲得表示待測試應用程序窗體的 type 對象。然后我使用 type.getmethod 獲得指定方法的信息,并調用 methodbase.invoke 執行指定方法。invoke 接受兩個參數。第一個是要對其調用方法的窗體實例,第二個是方法的參數數組。對于按鈕控件單擊方法這種情況,簽名如下所示:

private void button1_click(object sender, system.eventargs e)為了滿足 button1_click 方法的參數需要,我需要傳遞一個表示發送方的對象和一個表示可選事件數據的 eventargs 對象。對于按鈕單擊,我忽略了第一個參數的值,雖然對于實際的測試系統,我應該將控件作為導致調用該方法的發送方加以傳遞(該方法的實現可能依賴于對控件的訪問,如果這個事件處理程序方法被當作多個控件的處理程序使用,則這個信息就特別有用)。對于第二個參數,我傳遞一個空的 eventargs 對象。

請注意,測試自動化是通過直接調用按鈕控件的相關方法模擬按鈕單擊的,而不是通過觸發事件模擬。當實際用戶單擊按鈕時,它會生成一個 windows 消息,該控件對該消息進行處理,并將其轉換成托管事件。這個事件會導致調用一個特定的(或一組)方法。所以如果應用程序為按鈕單擊事件關聯了錯誤的方法,ui 測試自動化不會捕捉到邏輯錯誤(雖然每次測試都會失敗,而且您會很快發現問題)。這個問題可以糾正,方法是獲取使用反射的事件的底層多路廣播委托,然后當事件引發時使用委托的 getinvocationlist 方法來獲得要調用的所有委托的列表。然后可以單獨調用每個委托。或者可以使用事件的 eventinfo 及其 getraisemethod 方法來獲取引發事件的方法的 methodinfo,但這樣做只返回一個自定義的引發方法,而且支持自定義引發方法的 microsoft 語言只有 c++ 和 microsoft 中間語言 (msil)。再次說明,所有這些問題都可以通過使用前面討論的 send keys 方法加以避免。

返回頁首
檢查應用程序狀態


在自動化通過模擬用戶鍵入和單擊來設置應用程序窗體的狀態之后,就可以檢查系統狀態來查看應用程序是否正確響應了(請參見圖 9)。

我設置了一個名為“pass”的布爾變量,將其設為 true — 我假設應用程序的狀態是正確的并檢查該狀態,如果有某個地方出錯,則將 pass 設為 false。檢查 textbox1 控件,確保其 text 屬性正確地設為“red”。然后檢查以確保 combobox1 的值為“blue”,而且 listbox1 顯示正確的消息“result is purple”。如果一切檢查都通過,則打印 pass 消息,否則打印 fail 消息。

檢查應用程序系統狀態的關鍵是我編碼的 getcontrolpropertyvalue 方法,如圖 10 所示。首先使用 object.gettype 創建表示應用程序窗體的 type 對象。然后使用 type.getfield 獲取指定控件的信息。接下來再使用 gettype 獲取表示控件的 type 對象。最后使用 getproperty 獲取控件的指定屬性的信息,并使用 getvalue 方法獲取控件屬性值。getvalue 需要一個索引對象參數,因為屬性可被索引(例如,當我試圖獲取 listbox 控件的 items 屬性時)。

請注意,檢查 listbox1 控件中的文本比檢查 textbox1 控件中的文本要靈活一些。我使用我的 getcontrolpropertyvalue 方法訪問 items 屬性,然后使用 contains 方法進行檢查。

檢查應用程序狀態并記錄 pass 或 fail 結果之后,我就可以輕松地退出待測試應用程序:

console.writeline("/nclicking menu file->exit in 5 seconds . . . ");
thread.sleep(3500);
invokemethod("menuitem4_click", new object[] {null, new eventargs()} );

雖然當測試管理終止時待測試應用程序也會終止,因為它們是在相同的進程中運行的,而且待測試應用程序是在后臺線程中運行的,但為了顯式清理分配的任何系統資源,最好是顯式通過測試管理退出應用程序。

返回頁首
討論


如果您在 .net 問世之前就想實現 ui 測試自動化,則實際上只有兩種選擇。第一,購買商業化的 ui 自動化工具。第二,使用 microsoft active accessibility (msaa) api 創建自己的 ui 自動化工具。我所介紹的系統很好地補充了另外兩種策略。有幾種優秀的商業化 ui 自動化工具可供您使用。這些工具的優點是它們的功能齊全。而缺點是您需要為它們付費,有一段陡峭的學習曲線,而且當您需要修改功能時不允許您訪問源代碼。使用 msaa 可以讓您完全控制您的自動化工具,但它需要很長的時間去學習。實際上,在我做過的幾個項目中,基于 msaa 的 ui 測試自動化很可能像待測試應用程序那樣復雜!

我這里提到的自動化 ui 測試方法已經成功地在幾個大中型的產品中使用。由于它可以快速輕松地實現,所以當待測試系統很不穩定時,可以早早地將它用于產品周期中。然而,由于這個 ui 測試系統相對輕量級,所以它無法應付所有可能的 ui 測試情況。您可以采用多種方式修改和擴展這一設計。因為此次介紹的意圖是讓讀者有個初步的了解,為了更加清楚和簡單,我刪除了大部分錯誤檢查并對大多數信息進行了硬編碼。有必要向測試自動化添加許多錯誤檢查代碼 — 畢竟您期待的是發現錯誤。

根據您的生產環境,您可以對測試系統的一些部分進行參數化。在測試術語方面,我提到的系統稱為測試方案 (test scenario) — 控制待測試應用程序狀態的一連串操作(與測試用例 (test case) 不同,后者通常指較小的操作,如傳遞一個參數給方法,檢查返回值。)例如,要參數化該方案,您可以創建一個如下所示的輸入文件:

[set state]
textbox1:text:yellow
textbox1:text:red
combobox1:selecteditem:green
combobox1:selecteditem:blue
button1:button1_click
[check state]
textbox1:text:red
combobox1:selecteditem:blue
listbox1:items:result is purple

然后您可以讓您的測試自動化讀取、解析和使用該文件中的數據。您還可以使用 xml 或 sql 作為測試方案輸入數據。我所介紹的測試系統將其結果記錄到命令外殼中。您可以很輕松地通過命令行將結果重定向到文本文件,或者重寫自動化來直接記錄結果。

下一代 windows(代號為“longhorn”)將引入一個代號為“avalon”的新的表示子系統。avalon 會將我介紹的 ui 測試自動化概念提到更高的層次。我們亟待為所有 ui 元素的自動化提供平臺級別的支持,并為所有用戶控件公開一致的對象模型。這樣可以讓開發人員和測試人員快速輕松地創建極為強大的 ui 測試自動化。本專欄中的技術是對革命性的 avalon 的工作方式的一個提示。

在 .net 之前,編寫自動化通常是一個很耗資源的任務,而測試自動化(特別是 ui 測試自動化)通常被置于產品任務優先級列表的最底層。但有了 .net 之后,只需要花費以前所用時間的一小部分,就可以編寫出非常強大的測試自動化。


請將您要給 james 的問題和建議發送到 [email protected]。

james mccaffrey 就職于 volt information sciences, inc.,負責對在 microsoft 工作的軟件工程師進行技術培訓。他參與開發多種 microsoft 產品,包括 internet explorer 和 msn search。您可以通過 [email protected] 或 [email protected] 與 james 取得聯系。

上一篇:ADO 與ADO.NET

下一篇:.net下開發COM+組件

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 齐齐哈尔市| 兰州市| 旬邑县| 涿鹿县| 襄樊市| SHOW| 和田市| 铜陵市| 福贡县| 安康市| 樟树市| 罗源县| 阿拉善盟| 蒲江县| 新干县| 延津县| 晋中市| 泸溪县| 伊春市| 土默特右旗| 固镇县| 苏尼特右旗| 乌兰浩特市| 吉首市| 郧西县| 元朗区| 治多县| 油尖旺区| 海兴县| 南乐县| 洞头县| 陈巴尔虎旗| 增城市| 新河县| 个旧市| 灵石县| 方正县| 华蓥市| 莒南县| 甘泉县| 牟定县|