以往我們要測試桌面應用程式得透過 CodeUI,我對他的體驗不是很好,但現在可以改用 Appium+WinAppDriver 囉,連微軟也是這麼建議,立馬來試用看看
https://docs.microsoft.com/zh-tw/visualstudio/test/use-ui-automation-to-test-your-code?view=vs-2017
甚麼是 WinAppDriver
他是一套類 Selenium 的 UI 測試框架,先來看看他的架構,由下圖可以得知 WinAppDriver 可以驅動 Windows 的應用程式,用 JSON 跟外部程式進行資料交換、控制,WinAppDriver 也整合 Appium,我們就能夠過 Appium 的語法來控制 UI
下圖出自:https://www.slideshare.net/jeremykao92/winappdriver-development
github:https://github.com/Microsoft/WinAppDriver#testing-a-universal-windows-platform-application
甚麼是 Appium
Appium 是一套開源的應用程式自動測試工具,需要更多的資訊請,參考:https://medium.com/@kentchen_tw/appium-1-app-測試自動化框架-c929d8f7a439
appium-dotnet-driver 就是直接整合原生 .NET 程式的 Library
github:https://github.com/appium/appium-dotnet-driver
本文連結
開發環境
- VS 2017
- .NET Framework 4.7.2
- Windows 10 Enterprise ver.1803 ,OS build 17134.648
安裝及設定
設定開發模式
Windows Application Driver
- 下載並且安裝 https://github.com/Microsoft/WinAppDriver/releases
- 裝好之後路徑是 C:\Program Files (x86)\Windows Application Driver
- 使用管理員權限運行 WinAppDriver.exe,成功的話會建立起一個測試用的Web Server,預設是 4723,當然你也可以改
參考:https://github.com/Microsoft/WinAppDriver#installing-and-running-windows-application-driver
Inspect.exe
這是用來觀察應用程式相關的資訊,比如 Handler、Title,要先安裝 Windows 10 SDK,這可以在 Visual Studio Installer 裡面找的到,以我的環境為例,只裝了最新版本的 SDK。
在 C:\Program Files (x86)\Windows Kits\10 路徑可以看到有哪些 SDK 版本,找到 inspect.exe 然後運行,我用 C:\Program Files (x86)\Windows Kits\10\bin\10.0.17763.0\x64\inspect.exe
他會跟著你目前的焦點,秀出那個應用程式的相關資訊,比如說:AutomationId 是 UI 上面會出現的唯一值,等會就可以透過 Appium.WebDriver 找到這個 Id
WinAppDriver UI Recorder
XPath,這是怎麼知道的呢?
下載 WinAppDriver UI Recorder v1.0 RC,https://github.com/Microsoft/WinAppDriver/releases
用可以找到滑鼠焦點的 XPath,超方便的啦,只不過用起來會鈍鈍的,可能不斷的在捕捉滑鼠鍵盤事件忙了點
還可以錄製測試步驟,轉成 C#
實作
- 建立一個桌面應用程式專案,不一定要建立這個專案,可以從現有的應用程式玩玩看
Nuget 安裝 Appium.WebDriver
建立一個單元測試專案
- Install-Package Appium.WebDriver
- 開始寫測試之前需要先準備測試環境
設定 App Capabilities
傳統的應用程式就傳入絕對路徑,測試專案跟桌面應用程式放在同一層目錄,這裡我為了要不直接寫死路徑,做了一些處理;先取得方案路徑在找到 app.exe,當然,可以改專案設定把 bin\debug 給拿掉
var projectName = "App"; string solutionPath = Path.GetFullPath(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "..\\..\\..\\")); var targetAppPath = Path.Combine(solutionPath, projectName, "bin", "debug", "app.exe"); DesiredCapabilities appCapabilities = new DesiredCapabilities(); appCapabilities.SetCapability("app", targetAppPath);
如果是 UWP 應用程式則是傳入Package ID,比如
appCapabilities.SetCapability("app", "Microsoft.WindowsAlarms_8wekyb3d8bbwe!App");
更多的設定,請參考:https://github.com/Microsoft/WinAppDriver#supported-capabilities
建立 WindowsDriver
傳入 Windows App Driver 的 URI
WindowsDriver = new WindowsDriver<WindowsElement>(new Uri("http://127.0.0.1:4723"), appCapabilities);
更多的設定,請參考https://github.com/Microsoft/WinAppDriver#testing-a-classic-windows-application
前置作業的完整代碼如下
開始測試之前建置 WindowsDriver 環境,結束之後關掉 WindowsDriver
[TestClass] public class UnitTest1 { protected internal static WindowsDriver<WindowsElement> WindowsDriver; [ClassInitialize] public static void Setup(TestContext context) { var projectName = "App"; string solutionPath = Path.GetFullPath(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "..\\..\\..\\")); var targetAppPath = Path.Combine(solutionPath, projectName, "bin", "debug", "app.exe"); DesiredCapabilities appCapabilities = new DesiredCapabilities(); appCapabilities.SetCapability("app", targetAppPath); WindowsDriver = new WindowsDriver<WindowsElement>(new Uri("http://127.0.0.1:4723"), appCapabilities); } [ClassCleanup] public static void Cleanup() { WindowsDriver.CloseApp(); WindowsDriver.Dispose(); } }
開始寫測試
測試案例=需求,有需求才有測試
案例步驟
- 在 Id 文字方塊輸入yao
- 在 Password 文字方塊輸入123456
- 按下 Login 按鈕
- 預期得到一個彈跳視窗並呈現 Hi~yao
如下,翻成測試程式
[TestMethod] public void 輸入帳號密碼_按下登入_預期得到一個彈跳視窗並呈現Hiyao() { WindowsDriver.FindElementByAccessibilityId("Id_TextBox").SendKeys("yao"); WindowsDriver.FindElementByAccessibilityId("Password_TextBox").SendKeys("123456"); WindowsDriver.FindElementByAccessibilityId("Login_Button").Click(); var messageBox = WindowsDriver.FindElementByClassName("#32770"); var title = messageBox.Text; var messageText = messageBox.FindElementByXPath("//Text[@Name='Hi~yao']").Text; Assert.AreEqual("Title", title); Assert.AreEqual("Hi~yao", messageText); WindowsDriver.FindElementByXPath("//Button[@Name='OK']").Click(); }
桌面應用程式的驗證,就是看那一個視窗的效果是否如預期,視窗、控制項都有一個唯一值 Handler,只要有這個就能下 Send/Post Message 存取它,現在我們藉由 FindElement 幫我們找出 Handler並且存取,簡單多了!
Appium API
Appium API 提供了一些常用的搜尋讓我們能快速的找到 UI 控制項
FindElementByAccessibilityId:根據 Id 找控制項,對應到 Inspect 的 AutomationId,這個是唯一值,用它最好找。
FindElementByClassName:根據 Class Name 找控制項,對應到 Inspect 的 ClassName,可能不是唯一。
FindElementByXPath:當我們用到 DataBinding ,讓動態長出來的 UI,不會有唯一值,這時候就可以用這個。
Appium API 所對應到 Inspect 的 屬性如下表,出自 https://github.com/Microsoft/WinAppDriver#supported-locators-to-find-ui-elements
若有謬誤,煩請告知,新手發帖請多包涵
Microsoft MVP Award 2010~2017 C# 第四季
Microsoft MVP Award 2018~2022 .NET