下記記事にある通り、「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」ボタンをクリックすると、操作を記録することができます。
生成されたコード
電卓を操作した際に生成されたコードが下記になります。
// 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」を追加してください。)
using System;
using OpenQA.Selenium.Appium.Windows;
using OpenQA.Selenium.Remote;
namespace WinAppDriverTest
{
class Program
{
private const string WindowsApplicationDriverUrl = "http://127.0.0.1:4723";
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を使ったコードが書きやすくなるツールなのだと思います。
まだ、出始めのツールなので、今後に期待ですね!























この記事へのコメントはありません。