測試自動化
測試場景系統由一個單一文件組成。我打算把我的測試集實現為一個C#控制臺應用程序,但你將會看到,我能使用任何與.Net兼容的語言 (例如,Visual Basic .NET),該技術也能用于任何程序(例如,一個Windows程序)和測試框架(例如,NUnit)。場景的整體結構顯示在圖3中。首先,我向“Microsoft Internet Controls”這個優秀的COM組件添加了一個引用(reference)。這是shdocvw.dll模塊的一個別名,該模塊擁有操作基于Windows的瀏覽器(例如IE和Windows Explorer)的能力。然后我向Microsoft.mshtml.Net組件添加了一個引用。這是mshtml.dll模塊的一個別名,該模塊擁有訪問HTML元素的能力。我向兩個相應的名字空間增加了“using”聲明,這樣我就不需完整驗證他們的類了。我也針對System.Diagnostics和System.Threading分別增加了“using”聲明,這樣我容易引用前者的Process類,也能在我合適的時候引用后者的Thread.Slepp方法來暫停我的自動化過程。
圖3
Figure 3 Test Scenario Structure using System; using System.Threading; using System.Diagnostics; using SHDocVw; using mshtml; namespace RunTest { class Class1 { static AutoResetEvent documentComplete = new AutoResetEvent(false); [STAThread] static void Main(string[] args) { try { // Launch IE // Attach InternetExplorer object // Establish DocumentComplete event handler // Load app under test // Manipulate the app // Check the app's state // Log 'pass' or 'fail' // Close IE } catch(Exception ex) { Console.WriteLine("Fatal error: " + ex.Message); } } private static void ie_DocumentComplete(object pDisp, ref object URL) { documentComplete.Set(); } } } |
這項技術的一個關鍵是要有能力確定一個Web頁面/文檔/應用程序何時已經在IE中充分裝載了。我定義了一個類范圍的AutoResetEvent對象documentComplet,我使用該對象來標記一個已經充分裝載了文檔的等待線程。
static AutoResetEvent documentComplete = new AutoResetEvent(false);
馬上,我就會詳細介紹這里的細節。我由向命令行中打印一條狀態信息來開始我的測試場景。然后我聲明了一個Boolean類型的變量pass并把它設為false。我假設測試場景會失敗,如果我檢測到應用程序的最后狀態是正確的,我修正我的假設并把pass變量設為true。下一步我聲明了一個InternetExplore對象“ie”:
Console.WriteLine("\nStart test run");
bool pass = false;
InternetExplorer ie = null;
InternetExplorer類是在SHDocVw名字空間中定義的。該類有很多方法操縱Internet Explorer的一個實例,但是由你決定啟動Internet Explorer并把兩者相關聯,如下所示:
// launch explorer
Console.WriteLine("\nLaunching an instance of IE");
Process p = Process.Start("iexplore.exe", "about:blank");
if (p == null) throw new Exception("Could not launch IE");
Console.WriteLine("Process handle = " + p.MainWindowHandle.ToString());
// find all active browsers
SHDocVw.ShellWindows allBrowsers = new SHDocVw.ShellWindows();
Console.WriteLine("Number active browsers = " + allBrowsers.Count);
if (allBrowsers.Count == 0) throw new Exception("Cannot find IE");
我使用System.Diagnostics.Process名字空間中的Start方法來啟動一個Internet Explorer(iexplore.exe)并裝載空白頁面“about:blank”;Start方法返回對創建進程對象的一個引用。然后我初始化了一個名為allBrowsers的ShellWindows對象。這個對象掌握了對所有ShellWindows對象的引用,也掌握了對瀏覽器的引用(包括Windows Explorer的實例,我剛才啟動的Internet Explorer的實例和之前啟動的Internet Explorer的實例)。我使用Count屬性來顯示關于目前活動瀏覽器的診斷信息,以便確保Internet Explorer成功啟動了。測試自動化的下一步是把新的進程與Internet Explorer對象關聯起來:
Console.WriteLine("Attaching to IE");
for(int i=0; i < allBrowsers.Count && ie == null; i++)
{
InternetExplorer e = (InternetExplorer)allBrowsers.Item(i);
if (e.HWND == (int)p.MainWindowHandle) ie = e;
}
if (ie == null) throw new Exception("Failed to attach to IE");
可能有好幾個Internet Explorer的實例正在運行,所以我需要辨明哪個是我的測試場景啟動的,以便我能把我的InternetExplorer變量ie與正確的實例關聯起來。記住,我把測試啟動的Internet Explorer捕獲到一個進程對象p中了。所以我遍歷ShellWindows中的每一個對象,檢查他們的句柄或指針是否和測試啟動的進程的主窗口句柄一致。我有時候采用的一個替換的方法是假設只有我的測試Internet Explorer實例允許運行。如果有多個Internet Explorer實例運行,我拋出一個異常。這個假設運行我把測試Internet Explorer與下面的代碼簡單關聯起來: