Windows UIA自動化測試框架學習--獲取qq好友列表
前段時間應公司要求開發一款針對現有WPF程式的自動化測試工具,在網上查資料找了一段時間,發現用來做自動化測試的框架還是比較多的,比如python的兩個模組pywinauto和uiautomation,但是pywinauto主要是封裝Win32的api,只侷限於winform框架,而python中的uiautomation其實是封裝的windows中的uia框架。基於專案效率考慮,所以最後決定使用windows中的UIAutomation框架。
這款WindowsUIA框架是同時支援wpf和winform,由於公司專案主要是wpf為主,所以以下學習和舉例也是基於wpf框架,沒有深入研究winform下的差異,但是大體上還是差不多的。
僅僅作為客戶端來invoke的話,只需要引用下面兩個dll即可,可以在.Net框架中查詢:UIAutomationClient.dll,UIAutomationTypes.dll
在UIA框架中,所有元素包括視窗和控制元件都表現為AutomationElement。一個程序中的UI在空間上分佈在一棵UI樹上面,只需要找到UI樹的根元素,就可以檢索到與之相關聯的其他任何元素
查詢視窗
查詢每個程序的根元素最常用的是根據控制元件控制代碼查詢,方法如下:
但是這個框架沒有提供檢索控制代碼的功能,所以需要和API配合使用:
private static extern IntPtr findWindow(string lpClassName, string lpWindowName);
根據這個API獲取某個視窗的控制代碼,根據這個視窗的控制代碼獲取到AutomationElement,然後就可以通過下面的方法來查詢其他元素
以上兩個方法可以搜尋到這顆UI樹上的所有子控制元件,例如查詢某個Name屬性為MyButton的Button控制元件並觸發它的點選事件,就可以這樣實現:
PropertyCondition typeProperty = new PropertyCondition(AutomationElement.IsInvokePatternAvailableProperty, true); PropertyCondition nameProperty = new PropertyCondition(AutomationElement.AutomationIdProperty, “MyButton”);//搜尋條件 AutomationElement ele = _mainAutomationElement.FindFirst(TreeScope.Subtree, new AndCondition(typeProperty, nameProperty)); if (ele != null) { if (ele.Current.IsEnabled) { InvokePattern pattern = (InvokePattern)ele.GetCurrentPattern(InvokePattern.Pattern); pattern.Invoke();//觸發點選事件 } }
需要注意的是WPF中控制元件的屬性對映到AutomationElement有以下對應關係
Control property in WPF | Property in AutomationElement |
Name | AutomationIdProperty |
Content | Name |
Title | Name |
視窗的Title和繼承ContentControl 的控制元件的Content 都會對映為AutomationElement中的Name屬性
通過上述方法,基本可以查詢到WPF中所有常用的控制元件,至於三方控制元件也有一定的相容性。
基於以上資訊,我們可以開發一個小工具,用於讀取QQ軟體的好友列表。
讀取QQ軟體的好友列表
這個小功能還是通過win32API+UIA框架實現的,獲取到qq好友列表中的成員備註名稱,圖中的好友姓名只取姓氏。
用到的API如下:
private const int MOUSEEVENTF_LEFTDOWN = 0x0002;//press the mouse left button
private const int MOUSEEVENTF_LEFTUP = 0x0004; //release the mouse right button
private const int MOUSEEVENTF_WHEEL = 0x800;//mouse wheel
[DllImport("user32.dll", EntryPoint = "FindWindow")]
private static extern IntPtr findWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll")]
private static extern int mouse_event(int dwFlags, int dx, int dy, int cButtons, int dwExtraInfo);
[DllImport("user32.dll", EntryPoint = "SetCursorPos")]
private static extern bool setCursorPos(int X, int Y);
第一個API是為了獲取qq視窗的控制代碼,第二個和第三個是用來模擬滑鼠操作。
主程式程式碼很簡單,基本流程是先檢索到列表名稱的控制元件,然後通過獲取座標控制滑鼠點選將列表展開,檢索該列表中所有的成員。檢索完成後將列表重新隱藏,避免列表成員太多,列表太長,影響下一個列表的展開。
IntPtr ptr = findWindow(null,"QQ"); List<string> tables = new List<string>() {"高中","小學","初中","網友","大學"};//好友列表名稱 AutomationElement _mainElement = AutomationElement.FromHandle(ptr); foreach (var item in tables) { PropertyCondition type = new PropertyCondition(AutomationElement.IsControlElementProperty, true); PropertyCondition name = new PropertyCondition(AutomationElement.NameProperty, item); AutomationElement tableElement = _mainElement.FindFirst(TreeScope.Subtree, new AndCondition(type, name)); if(tableElement!=null) { Click(tableElement.GetClickablePoint().X, tableElement.GetClickablePoint().Y);//展開列表 AutomationElementCollection ac = _mainElement.FindAll(TreeScope.Subtree, new PropertyCondition(AutomationElement.IsSelectionItemPatternAvailableProperty, true)); Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine(tableElement.Current.Name+":"); Console.ForegroundColor = ConsoleColor.White; foreach (AutomationElement ele in ac) { Console.WriteLine(ele.Current.Name.Substring(0, 1) + "**"); } Click(tableElement.GetClickablePoint().X, tableElement.GetClickablePoint().Y);//重新隱藏列表 } } Console.ReadLine();
通過控制滑鼠的API和UIA框架基本可以實現模擬任何人為操作,對實現windows app自動化測試是一個不錯的選擇