在powershell中使用Windows UI Automation進行UI自動化測試

在使用Windows UI Automation的時候,要查找某一UI元素,通常要先獲取一個RootElement——桌面。其他所有的Element都是基於RootElement之上。該如何獲取RootElement呢?

[Reflection.Assembly]::LoadWithPartialName("UIAutomationClient")
$rootElement = ([Windows.Automation.AutomationElement]::RootElement)


如果按照如上的方式加載Assembly,可以獲得到RootElement,但是RootElement中的信息很不完整,甚至是嚴重的缺失,幾乎不能正常使用
發生這種問題的原因是,UIAutoimation的API只能夠在STA(Single-Thread Apartment)環境中運行,而powershell目前只能在MTA(Multi-Thread Apartment)環境中運行,而且不能夠進行切換,導致運行時不兼容。有關STA和MTA可以參考MSDN中Apartment的定義或者STA和MTA雜談
通常編寫的.Net程序默認都是STA的,因此可以編寫一個.Net的DLL獲取RootElement,然後在powershell中使用,如下:

using System;
using System.Windows.Automation;
public static class AutomationHelper
{
public static object GetRootElement()
    {
        return System.Windows.Automation.AutomationElement.RootElement;
    }
}


然後利用Add-Type這個Cmdlet可以很方面將上述C#代碼編譯爲庫文件並加載到powershell環境中使用(不要忘記附加的ReferencedAssemblies):

$source = @'
using System;
using System.Windows.Automation;
public static class AutomationHelper
{
public static object GetRootElement()
    {
        return System.Windows.Automation.AutomationElement.RootElement;
    }
}
'@
Add-Type -TypeDefinition $source -ReferencedAssemblies 'C:\Program Files\Reference Assemblies\Microsoft\Framework\v3.0\UIAutomationClient.dll'


這樣,就已經將C#的源碼編譯爲臨時的DLL文件,並且以STA的方式加載到powershell環境中了。

當成功獲得了我們需要的RootElement,我們就已經成功一半了,接下來的事情就是要通過各種條件使用UIAutomation的API來查找我們指定的UI元素了。以notepad爲例子,如下:

$source = @'
using System;
using System.Windows.Automation;
public static class AutomationHelper
{
public static object GetRootElement()
    {
        return System.Windows.Automation.AutomationElement.RootElement;
    }
}
'@
Add-Type -TypeDefinition $source -ReferencedAssemblies 'C:\Program Files\Reference Assemblies\Microsoft\Framework\v3.0\UIAutomationClient.dll'

[diagnostics.process]::start("notepad.exe")
start-sleep 1
$rootElement = [AutomationHelper]::GetRootElement()
$window = new-object System.Windows.Automation.PropertyCondition([Windows.Automation.AutomationElement]::ControlTypeProperty, [Windows.Automation.ControlType]::Window)
$windowtext = new-object Windows.Automation.PropertyCondition([Windows.Automation.AutomationElement]::NameProperty), "Untitled - Notepad"
$window = new-object Windows.Automation.AndCondition ($window, $windowtext)
$windowElement = $rootElement.FindFirst("Children", $window)
# Get the menubar
$menuBar = new-object Windows.Automation.PropertyCondition([Windows.Automation.AutomationElement]::AutomationIdProperty), "MenuBar"
$menuBarElement = $windowElement.FindFirst("Children", $menuBar)
$itemOne = new-object Windows.Automation.PropertyCondition([Windows.Automation.AutomationElement]::AutomationIdProperty),"Item 1"
$itemOneElement = $menuBarElement.FindFirst("Children", $itemOne)
# Expand the File menu from the menubar
$itemOneElement.GetCurrentPattern([System.Windows.Automation.ExpandCollapsePattern]::Pattern).Expand()

步驟爲先設置PropertyCondition,然後以要查找的根節點元素開始用FindFirst()查找第一次出現的或者用FindAll()返回所有符合給定的PropertyCondition的元素,"Children"這個參數的類型是System.Windows.Automation.TreeScope,具體含義可以查閱MSDN。

根據不同的PropertyCondition組合,我們可以封裝適用的Powershell UI Automation API,例如:GetElementById(),GetTextElementByName(),ClickButtonElementById()等等

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章