WinAppDriverのサンプルを動かすまで

Windowsアプリで自動化UIテストを導入したくて調べた結果、MS謹製のWindows Application Driver（以下WinAppDriver）というのが使えそうだとわかりました。Visual StudioのEnterpriseには内蔵のテストツールがあるみたいですが、2019で打ち止めで以後はこっちを使ってね、という記述も見られました。高いEnterpriseを買わなくても無料で使えるんだから有り難いことです。

早速Githubにあるサンプルを動かしてみようとチャレンジしたんですが存外苦労したのでメモ。

# 用語整理
WinAppDriverについてググっているとSeleniumとかAppiumとか色々なツールの名前が出てきて混乱します。私の理解した範囲で一応整理。間違いなどあれば是非ご指摘ください。

- テストスクリプト
「ボタンをクリックする」「結果が0になってるかチェック」みたいな手順を記したスクリプト。テストランナーごとに様々なプログラム言語で記述できる。単に１行１動作で記述するだけでなく、繰り返しやメソッド化もできるので、慣れた言語で記述できるのは便利。

- テストランナー
テストスクリプトを解釈してドライバーに制御指示を出す実行基盤。対象がブラウザならWebドライバー、Windowsの制御ならWinAppDriverなどを呼び出す。

- Selenium
定番自動化ランナー。ここではあまり気にしなくて良い。

- Appium
これも定番。Seleniumの派生？拡張版？node.jsで動く。MSがWinAppDriverをAppiumから呼びだせるようにしてくれたおかげで、AppiumでWinアプリを制御できるようになった。
Appiumありきで、WebアプリやWinアプリ、モバイルアプリなどに対して駆使したい場合は単体でインストールや設定をして使うんでしょうけど、今回のサンプル実行する限りではVisual Stuidoからプラグインとして導入されるので、あまり意識しなくてもOK。

- WinAppDriver
Windows10をスクリプトで自動制御するための文字通りドライバー。Githubにツール本体が公開されているがオープンソース化はされていない。公開リポジトリで管理されているのはドキュメントやサンプルのみ。それらをクローンして使うのとは別に、リリース版バイナリのインストーラーを落としてきてインストールする必要ある（後述）。

- inspect.exe
Windows SDKに含まれるツール。Windows上で開いてるウインドウ内のボタンなどGUIコンポーネントの名前などを調べることができる。WinAppDriverとは直接関係ないけどスクリプトを作るのに欠かせないユーティリティ。

- WinAppDriver UIレコーダー
ユーザの操作を記録しC#のテストスクリプトを生成してくれるツール。実際の運用ではゼロからスクリプトを書くより、これで大雑把に記録した上で修正を加えていく形になろうかと。願わくは次記事で触れたい。


# サンプルを動かすまで
WinAppDriverの公式リポジトリが[こちら](https://github.com/Microsoft/WinAppDriver)。そこからリンクされている電卓アプリを操作するサンプルを解説した動画が[こちら](https://www.youtube.com/watch?v=XAJVpvaEchY)。テストはVisual Studioで開けるC#プロジェクトとして提供されている。
クリーンな環境ではないので、Appiumを動かすのにnode.jsが別途必要なのかはちょっとわからなかったですが、git bashでnpmが見つからないのでたぶん入ってなさげ（でも動いた）。

## Windows 10を開発者モードにする
ここらへん参照。
https://www.ipentec.com/document/windows-windows-10-set-developer-mode。

## inspect.exe（Windows SDK）の導入
既に入ってたので憶えてないけど、たぶんここら辺からバージョンに応じてダウンロード。
https://developer.microsoft.com/en-us/windows/downloads/sdk-archive
動画で説明されているパスではなく、ウチでは

```
C:\Program Files (x86)\Windows Kits\10\bin\10.0.17763.0\x64\inspect.exe
```
にあった。「10.0.17763.0」当たりはWindows10のバージョンにあわせて。17763は2018 October Updateのことですね。

[追記] 様々なインストール方法があるみたいです。
https://stackoverflow.com/questions/34760513/how-to-install-the-inspect-tool-on-windows-10

## WinAppDriver本体の導入
GithubのReleaseページからWindowsApplicationDriver.msiをダウンロードしてインストール。今回は1.1.1を使用。実行バイナリは

```
C:\Program Files (x86)\Windows Application Driver\WinAppDriver.exe
```

とかになるでしょう。起動するとこんな画面が出て待ち受け状態になるので、そのまま放置しておきます。
![SharedScreenshot4.jpg](https://qiita-image-store.s3.amazonaws.com/0/128639/46320310-daae-6e9d-3642-71a0fca9b792.jpeg)


## WinAppDriverリポジトリを取得
動画ではコマンドプロンプトからgitでcloneしています。私はSouceTreeで適当なディレクトリにクローンしました。git環境がない人はZIPで落として展開してもいいんじゃないでしょうか。

## Visual Studio 2017で準備
動画に従い、

```
\WinAppDriver\Samples\C#\CalculatorTest\CalculatorTest.sln
```
をVisual Studioで開きます。
依存ライブラリが足りないので、
`ツール -> NuGetパッケージマネージャー -> ソリューションのNuGetパッケージの管理`
を開き、「復元」ボタンで必要なものを自動インストールします。ここでいくつかのライブラリには更新が出てくると思いますが、アップデートするとダメなようです。すべて最新版にしてしまうと、テスト実行時に

```
DesiredCapabilitiesは旧形式です
(DesiredCapabilities are no longer supported.)
```
的なエラーがでます。サンプルプロジェクトで指定されたバージョンをそのまま使っておきます。
参考: https://github.com/Microsoft/WinAppDriver/issues/497

これでビルドは通るんじゃないかと思います。直接実行はできないプロジェクトなので「ビルド」だけです。

次に動画で見えている左サイドバーのテストエクスプローラーがない場合は、
`テスト -> ウインドウ -> テストエクスプローラー`
で開きます。

![SharedScreenshot.jpg](https://qiita-image-store.s3.amazonaws.com/0/128639/c94ecf83-5c42-1dde-f926-33b8a35a0b11.jpeg)

こんなリストが出てくると思います（写真はパスした後なので緑チェックアイコンになってますが、最初は全て水色！アイコンです）。Addition（足し算）、Division（割り算）といった５つのスクリプトが存在します。個別に右クリックして「選択したテストの実行」で実行できます。

しかし実際には何もおこりません。「出力」をみるとこんな感じで「0 が実行されました」となっており、１つも実行されてなさげ。

![SharedScreenshot2.jpg](https://qiita-image-store.s3.amazonaws.com/0/128639/1742695b-951c-ad10-de82-d59526366086.jpeg)

これを解決するには、
`ツール -> オプション ->テスト`
を開き、
`パフォーマンスを向上させるため、テスト アセンブリ フォルダーにあるか、runsettings ファイルに指定されているテスト アダプターのみを使用してください`
のチェックを外す必要があります。
![SharedScreenshot3.jpg](https://qiita-image-store.s3.amazonaws.com/0/128639/9931c237-e9a3-c54c-0249-61cbfb0d876e.jpeg)

参考: https://github.com/Microsoft/WinAppDriver/issues/573


これで「電卓」が起動するものの、Additionテストは例外が出てパス（合格）しないと思います。ボタン名などが英語版Windows前提で書かれており、日本語の「電卓」では指定されたボタンが見当たらないということのようです。

個別のテストメソッドはScenarioStandard.csファイルに書かれており、例えばAdditionはこんな風になっています。

```c#
        public void Addition()
        {
            // Find the buttons by their names and click them in sequence to peform 1 + 7 = 8
            session.FindElementByName("One").Click();
            session.FindElementByName("Plus").Click();
            session.FindElementByName("Seven").Click();
            session.FindElementByName("Equals").Click();
            Assert.AreEqual("8", GetCalculatorResultText());
        }
```
そこでinspect.exeを起動して、電卓の各ボタンを調べてみるとNameプロパティの内容がわかります。日本語版の「電卓」では以下のように修正する必要がありました。

```c#
        public void Addition()
        {
            // Find the buttons by their names and click them in sequence to peform 1 + 7 = 8
            session.FindElementByName("1").Click();
            session.FindElementByName("プラス").Click();
            session.FindElementByName("7").Click();
            session.FindElementByName("等号").Click();
            Assert.AreEqual("8", GetCalculatorResultText());
        }
```
また最初にリセットするclearメソッドや計算結果のテキストフィールド結果から余計な文字列を排除するGetCalculatorResultTextメソッドも、以下のように変更する必要がありました（コメント部分がオリジナル）。

```c#
public void Clear()
        {
            //session.FindElementByName("Clear").Click();
            session.FindElementByName("クリア").Click();
            Assert.AreEqual("0", GetCalculatorResultText());
        }
```

```c#
    private string GetCalculatorResultText()
        {
            //return calculatorResult.Text.Replace("Display is", string.Empty).Trim();
            return calculatorResult.Text.Replace("表示は ", string.Empty).Replace(" です", string.Empty).Trim();

        }
```

ちなみに、割り算のDivisionテストではFindElementByName()メソッドの代わりにFindElementByAccessibilityId()が使われ、num8Buttonという識別子でアクセスしています。

```c#
    session.FindElementByAccessibilityId("num8Button").Click();
```

かけ算と引き算ではFindElementByXPath

```c#
    session.FindElementByXPath("//Button[@Name='Nine']").Click();
```
が使われています。これらは言語（リージョン）に依存しなさそげ。ただしXPathはUWPとかWPFとかXAMLでUIデザインされてるアプリ向けかな？

いずれにせよ開発時点でここら辺も横着しないで系統立てて名付けしておくと、評価が捗りそうですね。

ということでいくつかつまづきましたが、これで自動的に電卓が自動的に起動されてポチポチボタンがクリックされて結果の照合までは自動化することができました。

実際のスクリプトはもっと複雑になるしボタン名をいちいち照合するのも大変なので、前述のUIレコーダーを使ってざっくりスクリプトを作るのが合理的なんでしょう。次回はそちらにもチャレンジしたいと思います。