摘 要: 分析了錄制回放技術(shù)的基本原理和缺陷,運用WIN32API和.NET反射機制,設(shè)計了一個改進(jìn)的輕量級GUI自動化測試框架,解決了當(dāng)前測試自動化中出現(xiàn)的一些棘手問題。
關(guān)鍵詞: GUI;自動化測試;反射
軟件測試是保證軟件質(zhì)量的有效手段。目前,在GUI自動化測試中,很多軟件體系都采用錄制回放技術(shù)。這種技術(shù)要求測試者通過鼠標(biāo)和鍵盤的點擊進(jìn)行工作,腳本記錄事件,然后以自動化測試的方式進(jìn)行回放。記錄下來的測試腳本必須經(jīng)過編輯和調(diào)試之后插入驗證和檢查點。產(chǎn)生的腳本通常是硬編碼,需要測試人員對腳本進(jìn)行編輯以及參數(shù)化操作。同時,界面元素屬性的任何變化都會影響腳本的運行,有時甚至需要重新錄制腳本。
1 .NET中的反射機制
通常,應(yīng)用程序(包括桌面程序和Web應(yīng)用)都由一些基本的界面控件組成,所有的軟件指令都是通過控件以事件或消息的形式傳遞給后臺處理。GUI自動化測試的本質(zhì)是對GUI中的控件元素提供編程手段[2]。在基于GUI對象識別和控制的自動化測試工具中,過去一直依賴于Windows API函數(shù)的調(diào)用。而隨著新的編程語言和平臺的出現(xiàn),涌現(xiàn)了很多新的語言特性,這些語言特性可用于自動化測試工具的設(shè)計,例如反射機制就是其中一項技術(shù)。
反射(Reflection)是.NET中的重要機制,通過反射可以在運行時獲得.NET中每一個類型(包括類、結(jié)構(gòu)、委托、接口和枚舉等)的成員,包括方法、屬性、事件及構(gòu)造函數(shù)等,還可以獲得每個成員的名稱、限定符和參數(shù)等。如果獲得了構(gòu)造函數(shù)的信息,即可直接創(chuàng)建對象,即使這個對象的類型在編譯時還不知道。程序集包含模塊,而模塊包含類型,類型又包含成員,反射則提供了封裝程序集、模塊和類型的對象。可以使用反射動態(tài)地創(chuàng)建類型的實例,將類型綁定到現(xiàn)有對象或從現(xiàn)有對象中獲取類型,然后調(diào)用類型的方法或訪問其字段和屬性[3]。
2 框架的整體設(shè)計
自動化測試框架的搭建基本上占了整個自動化測試工作量的40%,是自動化測試實施的一個重要組成部分。軟件自動化框架從本質(zhì)看是一系列的策略思想、規(guī)范文件和代碼的集合。本文提出一種改進(jìn)的輕量級的GUI自動化測試框架,該框架可以幫助用戶避免當(dāng)前測試工具出現(xiàn)的缺陷。此框架將具備以下五個特性:GUI控件自動搜索、自動生成和執(zhí)行測試腳本、基于數(shù)據(jù)驅(qū)動的原則、測試的自動驗證、使用編程語言開發(fā)??蚣艿恼w設(shè)計如圖1所示。從圖1可以看出,該框架讓測試人員從繁重的錄制工作中解放出來,將更多的時間和精力集中在測試用例的設(shè)計中。
3 框架具體開發(fā)
3.1 加載被測試程序
為了測試GUI應(yīng)用程序,必須在測試工具中運行被測程序使兩個程序交互。使用Assembly定義和加載程序集,加載在程序集清單中列出模塊,并從此程序集中查找類型,創(chuàng)建該類型的實例。為了使這兩個應(yīng)用程序?qū)崿F(xiàn)交互,必須通過多線程機制實現(xiàn)。下面是通過反射加載被測程序的核心代碼[4]:
Assembly asm=Assembly.LoadFrom(path);
Type t1=asm.GetType(formName);
testForm=(Form)asmCreateInstance(t1.FullName);
ParameterizedThreadStart pt=new ParameterizedThreadStart(AppRun);
Thread thread=new Thread(pt);
thread.Start(testForm);
private void AppRun(Form theForm)
{
Application.Run(theForm);
}
3.2 GUI控件搜索
大部分自動化功能測試工具,尤其是商業(yè)的測試工具,都是基于GUI對象識別技術(shù)設(shè)計的?;舅枷胧敲總€基于窗體的控件都是一個窗體,每個控件或窗體都有一個句柄來進(jìn)行訪問、操作和檢查。
實現(xiàn)GUI測試自動化的困難之一是測試工具并不知道被測程序中存在哪些GUI部件。錄制回放工具使用手工錄制過程暫時解決了這一問題。Win32 API中封裝了很多可用于自動化測試編程的函數(shù),這些函數(shù)可在編程語言進(jìn)行調(diào)用,實現(xiàn)自動化測試編程。本文的自動化GUI測試工具將采用Win32 API對被測程序進(jìn)行自動、系統(tǒng)、全面的控件搜索。實現(xiàn)該搜索將用到Win32 API中封裝的可用于自動化測試編程的函數(shù),包括:GetWindowRect、mouse_event、GetCursorPos和WindowFromPoint函數(shù)等。GetWindowRect函數(shù)返回指定窗口的邊框矩形的尺寸。該尺寸以相對于屏幕坐標(biāo)左上角的屏幕坐標(biāo)給出。通過使用這個函數(shù)可以計算出窗口的寬度和高度。mouse_event函數(shù)能模擬鼠標(biāo)擊鍵和鼠標(biāo)動作。GetCursorPos函數(shù)檢取光標(biāo)的位置,并以屏幕坐標(biāo)來表示。使用WindowFromPoint函數(shù)能獲得包含指定點的控件的句柄。一旦得到了窗口的句柄,就能得到控件的文本、類名以及父窗口的句柄。為了對界面進(jìn)行徹底的控件搜索,該框架將使用嵌套循環(huán),從界面的左上角到界面的右下角依次移動鼠標(biāo)進(jìn)行控件識別,并將結(jié)果保存到對象庫中[5]。
該模塊實現(xiàn)的偽代碼如下:
RECT rt=new RECT();
GetWindowRect(iHandle,ref rt);
width=rt.Right-rt.Left; //得到界面的寬度
height=rt.Bottom-rt.Top; //得到高度
step=8; //鼠標(biāo)每次移動的像素
for (int x=0;x<width;x+=step)
{
for (int y=0;y<height;y+=step)
{
mouse_event(); //移動鼠標(biāo)到相應(yīng)的坐標(biāo)
GetCursorPos(); //得到坐標(biāo)點處的光標(biāo)
WindowFromPointGet(); //得到此處的控件句柄
GetWindowText(); //得到窗體的文本
GetClassName(); //得到控件的類別
GetParent(); //得到父窗體的句柄
if (the handle does not exist in object repository)
then save the infomation.
}
}
通過對界面的徹底搜索,可以得出控件的句柄、文本、類名、父窗體的句柄以及GUI控件間的層次關(guān)系。
3.3 生成測試用例
實現(xiàn)GUI測試自動化的另一個問題是測試工具不能按事件發(fā)生的順序來選擇和操作控件。傳統(tǒng)的測試工具通過錄制的方法記錄程序運行的順序,但是這種機制存在很多限制。本文設(shè)計的自動化測試框架的思路是經(jīng)過界面控件的徹底搜索后,控件的詳細(xì)信息會保持到對象庫中。此時,測試人員可以通過測試用例的輸入/輸出模塊來編寫測試用例。該模塊是一個可視化編輯器。測試用例編輯器從對象庫中導(dǎo)入對象信息,該模塊根據(jù)測試用例設(shè)計人員的操作順序自動產(chǎn)生事件的順序并將測試步驟保存到XML文件中。按事件發(fā)生的順序存儲的相關(guān)事件可以形成一個測試場景。測試用例編寫者可以對產(chǎn)生的測試場景進(jìn)行編輯,改變測試步驟的順序或者添加更多的事件。測試運行模塊將會從XML文件中讀取測試用例,按事件的順序執(zhí)行相應(yīng)的操作。
3.4 執(zhí)行并驗證測試
基于數(shù)據(jù)驅(qū)動的原則,在測試用例產(chǎn)生之后,測試用例文件驅(qū)動測試的執(zhí)行。不同的控件類型將從測試類庫中調(diào)用不同的測試執(zhí)行方法。該模塊采用反射機制來模擬用戶的操作。反射提供了延遲綁定,能模擬用戶的常用操作,如編輯控件文本、單擊按鈕等。調(diào)用控件的事件方法的關(guān)鍵是要用到反射中的MethodInfo.Invoke方法。如果沒有潛在的其他問題,可以像下面這樣調(diào)用控件的事件方法:
Type t1=testForm.GetType();
MethodInfo mi=t1.GetMethod(“button1_Click”,flags);
mi.Invoke(testForm,new object[]{null,EventArgs.Empty});
注意在調(diào)用該方法時要充分考慮線程的問題。該方法不是從被測應(yīng)用程序運行的線程被調(diào)用的,而是從測試工具本身的主線程中被調(diào)用的。因此,應(yīng)該通過調(diào)用Form.Invoke方法間接運行MethodInfo.Invoke方法[4]。
驗證測試過程中,為了得到控件的屬性或字段信息,將用到反射中的Form.GetType、Type.GetField、FieldInfo.GetValue、PropertyInfo.GetValue等方法。通過比較測試用例的預(yù)期結(jié)果和實際運行結(jié)果來決定測試結(jié)果。然后將測試用例的編號、預(yù)期結(jié)果、實際結(jié)果以及時間信息保存到XML文件中,同時可采用XSLT方式將測試結(jié)果以更友好的方式展現(xiàn)出來。
3.5 使用Windows調(diào)度程序
測試人員可能希望測試工具能在指定時間自動地運行測試,例如晚上11:00點。這樣,整個測試工作可以在下班之后進(jìn)行,到第二天就能看到測試運行的結(jié)果。事實上,Microsoft都包含一個能在給定時間執(zhí)行命令的程序。當(dāng)前版本中,這個程序是Scheduled Tasks,位于控制面板上。打開這個文件夾,會看到Add Scheduled Task 圖標(biāo),單擊它可以啟動向?qū)?。有一個重要的選項是Task選項卡上的Run文本框,如圖2所示??梢栽谠撐谋究蛑刑砑酉鄳?yīng)的參數(shù)來完成自動化測試[6]。
本文設(shè)計了一個輕量級的GUI自動化測試框架,該框架可以系統(tǒng)、全面、主動地實現(xiàn)控件搜索,避免了傳統(tǒng)測試工具中繁重的錄制過程。界面控件的任何改變也不會影響測試腳本的運行。該框架讓測試人員從繁瑣的錄制工作、測試腳本的編輯和驗證點的插入工作中解放出來,使測試人員能將更多的時間和精力集中到測試用例的設(shè)計中。
參考文獻(xiàn)
[1] BECK K. Test driven development: by example[M]. Addison-Wesley Professional, 2002.
[2] DUSTIN E, RASHKA J, PAUL J. Automated software testing introduction, management, and performance[M]. Boston addison Wesley,1999.
[3] 柳勝.軟件自動化測試框架設(shè)計與實踐[M].北京:人民郵電出版社,2009.
[4] ZHOU R Z, WEI Z K. Study on Application of .NET Reflection in Automated Testing[J]. ICACT, 2010,7-10:(797-800).
[5] MCCAFFREY J D. .NET test automation recipes: a problem-solution approach[M]. Apress, 2006.
[6] LI K L, WU M Q. Effective GUI testing automation: developing an automated GUI testing tool[M].王軼昆,譯.北京:電子工業(yè)出版社,2005.
[7] ROOT R, SWEENEY M R. A tester’s guide to .NET Programming[M].楊浩,譯.北京:清華大學(xué)出版社,2007:279-280.