下記記事にある通り、「WinAppDriver UI Recorder」が公開されたので、さっそく試してみました。
米Microsoftは20日(現地時間)、新しいオープンソースツール「WinAppDriver UI Recorder」を「Windows Application Driver」の一部としてリリースした。自動UIテストを作成するのに役立つ。
https://forest.watch.impress.co.jp/docs/news/1128952.html より
Microsoftは2018年6月20日(米国時間)、「Windows Application Driver」(WinAppDriver)コミュニティー向けの新しいオープンソースツール「WinAppDriver UI Recorder」(以下、UI Recorder)の公開を発表した。UI Recorderは、自動化されたUI(ユーザーインタフェース)テストのスクリプトを簡単に作成できるツールだ。
http://www.atmarkit.co.jp/ait/articles/1806/22/news036.html
WinAppDriver UI Recorderの使い方
GitHubのReleasesページにZip形式で圧縮されたバイナリファイルがありますが、今回はVisual Studio Community 2017でビルドしたものを使用しました。
WinAppDriver UI Recorderを使うとUI要素のXPathクエリを生成でき、上図の通り「Record」ボタンをクリックすると、操作を記録することができます。
生成されたコード
電卓を操作した際に生成されたコードが下記になります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 | // LeftClick on "One" at (75,20) Console.WriteLine( "LeftClick on \"One\" at (75,20)" ); string xp1 = "/Pane[@Name=\"デスクトップ 1\"][@ClassName=\"#32769\"]/Window[@Name=\"Calculator - Calculator\"][@ClassName=\"ApplicationFrameWindow\"]/Window[@Name=\"Calculator\"][@ClassName=\"Windows.UI.Core.CoreWindow\"]/Group[@ClassName=\"LandmarkTarget\"]/Group[@AutomationId=\"NumberPad\"][@Name=\"Number pad\"]/Button[@AutomationId=\"num1Button\"][@Name=\"One\"]" ; var winElem1 = MyDesktopSession.FindElementByXPath(xp1); if (winElem1 != null ) { winElem1.Click(); } else { Console.WriteLine($ "Failed to find element {xp1}" ); return ; } // LeftClick on "Two" at (44,20) Console.WriteLine( "LeftClick on \"Two\" at (44,20)" ); string xp2 = "/Pane[@Name=\"デスクトップ 1\"][@ClassName=\"#32769\"]/Window[@Name=\"Calculator - Calculator\"][@ClassName=\"ApplicationFrameWindow\"]/Window[@Name=\"Calculator\"][@ClassName=\"Windows.UI.Core.CoreWindow\"]/Group[@ClassName=\"LandmarkTarget\"]/Group[@AutomationId=\"NumberPad\"][@Name=\"Number pad\"]/Button[@AutomationId=\"num2Button\"][@Name=\"Two\"]" ; var winElem2 = MyDesktopSession.FindElementByXPath(xp2); if (winElem2 != null ) { winElem2.Click(); } else { Console.WriteLine($ "Failed to find element {xp2}" ); return ; } // LeftClick on "Three" at (36,20) Console.WriteLine( "LeftClick on \"Three\" at (36,20)" ); string xp3 = "/Pane[@Name=\"デスクトップ 1\"][@ClassName=\"#32769\"]/Window[@Name=\"Calculator - Calculator\"][@ClassName=\"ApplicationFrameWindow\"]/Window[@Name=\"Calculator\"][@ClassName=\"Windows.UI.Core.CoreWindow\"]/Group[@ClassName=\"LandmarkTarget\"]/Group[@AutomationId=\"NumberPad\"][@Name=\"Number pad\"]/Button[@AutomationId=\"num3Button\"][@Name=\"Three\"]" ; var winElem3 = MyDesktopSession.FindElementByXPath(xp3); if (winElem3 != null ) { winElem3.Click(); } else { Console.WriteLine($ "Failed to find element {xp3}" ); return ; } // LeftClick on "Plus" at (19,18) Console.WriteLine( "LeftClick on \"Plus\" at (19,18)" ); string xp4 = "/Pane[@Name=\"デスクトップ 1\"][@ClassName=\"#32769\"]/Window[@Name=\"Calculator - Calculator\"][@ClassName=\"ApplicationFrameWindow\"]/Window[@Name=\"Calculator\"][@ClassName=\"Windows.UI.Core.CoreWindow\"]/Group[@ClassName=\"LandmarkTarget\"]/Group[@AutomationId=\"StandardOperators\"][@Name=\"Standard operators\"]/Button[@AutomationId=\"plusButton\"][@Name=\"Plus\"]" ; var winElem4 = MyDesktopSession.FindElementByXPath(xp4); if (winElem4 != null ) { winElem4.Click(); } else { Console.WriteLine($ "Failed to find element {xp4}" ); return ; } // LeftClick on "Four" at (57,18) Console.WriteLine( "LeftClick on \"Four\" at (57,18)" ); string xp5 = "/Pane[@Name=\"デスクトップ 1\"][@ClassName=\"#32769\"]/Window[@Name=\"Calculator - Calculator\"][@ClassName=\"ApplicationFrameWindow\"]/Window[@Name=\"Calculator\"][@ClassName=\"Windows.UI.Core.CoreWindow\"]/Group[@ClassName=\"LandmarkTarget\"]/Group[@AutomationId=\"NumberPad\"][@Name=\"Number pad\"]/Button[@AutomationId=\"num4Button\"][@Name=\"Four\"]" ; var winElem5 = MyDesktopSession.FindElementByXPath(xp5); if (winElem5 != null ) { winElem5.Click(); } else { Console.WriteLine($ "Failed to find element {xp5}" ); return ; } // LeftClick on "Five" at (80,19) Console.WriteLine( "LeftClick on \"Five\" at (80,19)" ); string xp6 = "/Pane[@Name=\"デスクトップ 1\"][@ClassName=\"#32769\"]/Window[@Name=\"Calculator - Calculator\"][@ClassName=\"ApplicationFrameWindow\"]/Window[@Name=\"Calculator\"][@ClassName=\"Windows.UI.Core.CoreWindow\"]/Group[@ClassName=\"LandmarkTarget\"]/Group[@AutomationId=\"NumberPad\"][@Name=\"Number pad\"]/Button[@AutomationId=\"num5Button\"][@Name=\"Five\"]" ; var winElem6 = MyDesktopSession.FindElementByXPath(xp6); if (winElem6 != null ) { winElem6.Click(); } else { Console.WriteLine($ "Failed to find element {xp6}" ); return ; } // LeftClick on "Six" at (34,18) Console.WriteLine( "LeftClick on \"Six\" at (34,18)" ); string xp7 = "/Pane[@Name=\"デスクトップ 1\"][@ClassName=\"#32769\"]/Window[@Name=\"Calculator - Calculator\"][@ClassName=\"ApplicationFrameWindow\"]/Window[@Name=\"Calculator\"][@ClassName=\"Windows.UI.Core.CoreWindow\"]/Group[@ClassName=\"LandmarkTarget\"]/Group[@AutomationId=\"NumberPad\"][@Name=\"Number pad\"]/Button[@AutomationId=\"num6Button\"][@Name=\"Six\"]" ; var winElem7 = MyDesktopSession.FindElementByXPath(xp7); if (winElem7 != null ) { winElem7.Click(); } else { Console.WriteLine($ "Failed to find element {xp7}" ); return ; } // LeftClick on "Equals" at (59,29) Console.WriteLine( "LeftClick on \"Equals\" at (59,29)" ); string xp8 = "/Pane[@Name=\"デスクトップ 1\"][@ClassName=\"#32769\"]/Window[@Name=\"Calculator - Calculator\"][@ClassName=\"ApplicationFrameWindow\"]/Window[@Name=\"Calculator\"][@ClassName=\"Windows.UI.Core.CoreWindow\"]/Group[@ClassName=\"LandmarkTarget\"]/Group[@AutomationId=\"StandardOperators\"][@Name=\"Standard operators\"]/Button[@AutomationId=\"equalButton\"][@Name=\"Equals\"]" ; var winElem8 = MyDesktopSession.FindElementByXPath(xp8); if (winElem8 != null ) { winElem8.Click(); } else { Console.WriteLine($ "Failed to find element {xp8}" ); return ; } |
これをこのままコピー&ペーストしても動作しないので、一部コードを書き足して実行したところ、要素の取得で躓きました。
仕方が無いので、XPathの一部を編集したのが下記のコードです。
(「Windows Application Driverを試してみました。」記事に書いている通り、コードを実行する際はNuGetで「Appium.WebDriver」を追加してください。)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 | using System; using OpenQA.Selenium.Appium.Windows; using OpenQA.Selenium.Remote; namespace WinAppDriverTest { class Program { private const string CalculatorAppId = "Microsoft.WindowsCalculator_8wekyb3d8bbwe!App" ; protected static WindowsDriver<WindowsElement> session; static void Main( string [] args) { string serverPath = System.IO.Path.Combine( System.Environment.GetFolderPath( System.Environment.SpecialFolder.ProgramFilesX86 ), @"Windows Application Driver" , "WinAppDriver.exe" ); System.Diagnostics.Process.Start(serverPath); DesiredCapabilities appCapabilities = new DesiredCapabilities(); appCapabilities.SetCapability( "app" , CalculatorAppId); session = new WindowsDriver<WindowsElement>( new Uri(WindowsApplicationDriverUrl), appCapabilities); session.Manage().Timeouts().ImplicitlyWait(TimeSpan.FromSeconds(1.5)); // LeftClick on "One" at (75,20) Console.WriteLine( "LeftClick on \"One\" at (75,20)" ); string xp1 = "//*[@ClassName=\"ApplicationFrameWindow\"]/Window[@Name=\"Calculator\"][@ClassName=\"Windows.UI.Core.CoreWindow\"]/Group[@ClassName=\"LandmarkTarget\"]/Group[@AutomationId=\"NumberPad\"][@Name=\"Number pad\"]/Button[@AutomationId=\"num1Button\"][@Name=\"One\"]" ; var winElem1 = session.FindElementByXPath(xp1); if (winElem1 != null ) { winElem1.Click(); } else { Console.WriteLine($ "Failed to find element {xp1}" ); return ; } // LeftClick on "Two" at (44,20) Console.WriteLine( "LeftClick on \"Two\" at (44,20)" ); string xp2 = "//*[@ClassName=\"ApplicationFrameWindow\"]/Window[@Name=\"Calculator\"][@ClassName=\"Windows.UI.Core.CoreWindow\"]/Group[@ClassName=\"LandmarkTarget\"]/Group[@AutomationId=\"NumberPad\"][@Name=\"Number pad\"]/Button[@AutomationId=\"num2Button\"][@Name=\"Two\"]" ; var winElem2 = session.FindElementByXPath(xp2); if (winElem2 != null ) { winElem2.Click(); } else { Console.WriteLine($ "Failed to find element {xp2}" ); return ; } // LeftClick on "Three" at (36,20) Console.WriteLine( "LeftClick on \"Three\" at (36,20)" ); string xp3 = "//*[@ClassName=\"ApplicationFrameWindow\"]/Window[@Name=\"Calculator\"][@ClassName=\"Windows.UI.Core.CoreWindow\"]/Group[@ClassName=\"LandmarkTarget\"]/Group[@AutomationId=\"NumberPad\"][@Name=\"Number pad\"]/Button[@AutomationId=\"num3Button\"][@Name=\"Three\"]" ; var winElem3 = session.FindElementByXPath(xp3); if (winElem3 != null ) { winElem3.Click(); } else { Console.WriteLine($ "Failed to find element {xp3}" ); return ; } // LeftClick on "Plus" at (19,18) Console.WriteLine( "LeftClick on \"Plus\" at (19,18)" ); string xp4 = "//*[@ClassName=\"ApplicationFrameWindow\"]/Window[@Name=\"Calculator\"][@ClassName=\"Windows.UI.Core.CoreWindow\"]/Group[@ClassName=\"LandmarkTarget\"]/Group[@AutomationId=\"StandardOperators\"][@Name=\"Standard operators\"]/Button[@AutomationId=\"plusButton\"][@Name=\"Plus\"]" ; var winElem4 = session.FindElementByXPath(xp4); if (winElem4 != null ) { winElem4.Click(); } else { Console.WriteLine($ "Failed to find element {xp4}" ); return ; } // LeftClick on "Four" at (57,18) Console.WriteLine( "LeftClick on \"Four\" at (57,18)" ); string xp5 = "//*[@ClassName=\"ApplicationFrameWindow\"]/Window[@Name=\"Calculator\"][@ClassName=\"Windows.UI.Core.CoreWindow\"]/Group[@ClassName=\"LandmarkTarget\"]/Group[@AutomationId=\"NumberPad\"][@Name=\"Number pad\"]/Button[@AutomationId=\"num4Button\"][@Name=\"Four\"]" ; var winElem5 = session.FindElementByXPath(xp5); if (winElem5 != null ) { winElem5.Click(); } else { Console.WriteLine($ "Failed to find element {xp5}" ); return ; } // LeftClick on "Five" at (80,19) Console.WriteLine( "LeftClick on \"Five\" at (80,19)" ); string xp6 = "//*[@ClassName=\"ApplicationFrameWindow\"]/Window[@Name=\"Calculator\"][@ClassName=\"Windows.UI.Core.CoreWindow\"]/Group[@ClassName=\"LandmarkTarget\"]/Group[@AutomationId=\"NumberPad\"][@Name=\"Number pad\"]/Button[@AutomationId=\"num5Button\"][@Name=\"Five\"]" ; var winElem6 = session.FindElementByXPath(xp6); if (winElem6 != null ) { winElem6.Click(); } else { Console.WriteLine($ "Failed to find element {xp6}" ); return ; } // LeftClick on "Six" at (34,18) Console.WriteLine( "LeftClick on \"Six\" at (34,18)" ); string xp7 = "//*[@ClassName=\"ApplicationFrameWindow\"]/Window[@Name=\"Calculator\"][@ClassName=\"Windows.UI.Core.CoreWindow\"]/Group[@ClassName=\"LandmarkTarget\"]/Group[@AutomationId=\"NumberPad\"][@Name=\"Number pad\"]/Button[@AutomationId=\"num6Button\"][@Name=\"Six\"]" ; var winElem7 = session.FindElementByXPath(xp7); if (winElem7 != null ) { winElem7.Click(); } else { Console.WriteLine($ "Failed to find element {xp7}" ); return ; } // LeftClick on "Equals" at (59,29) Console.WriteLine( "LeftClick on \"Equals\" at (59,29)" ); string xp8 = "//*[@ClassName=\"ApplicationFrameWindow\"]/Window[@Name=\"Calculator\"][@ClassName=\"Windows.UI.Core.CoreWindow\"]/Group[@ClassName=\"LandmarkTarget\"]/Group[@AutomationId=\"StandardOperators\"][@Name=\"Standard operators\"]/Button[@AutomationId=\"equalButton\"][@Name=\"Equals\"]" ; var winElem8 = session.FindElementByXPath(xp8); if (winElem8 != null ) { winElem8.Click(); } else { Console.WriteLine($ "Failed to find element {xp8}" ); return ; } /* if (session != null ) { session.Quit(); session = null ; } */ Console.Write( "Press any key to continue . . . " ); Console.ReadKey( true ); } } } |
実行画面
下図の通り、WinAppDriverを使って問題なく電卓の操作ができました。
感想
軽く触ってみた感じ、要素のXPathを取得できる点は便利でしたが、生成されるコードは冗長で、Excelのマクロ記録機能のような印象を受けました。
UI要素を調べるツールとして、現時点(2018年6月)ではInspectの代わりになるものではなく、Inspectと併用することで、WinAppDriverを使ったコードが書きやすくなるツールなのだと思います。
まだ、出始めのツールなので、今後に期待ですね!
この記事へのコメントはありません。