Windows Application Driverを使ってWindowsFormのUIテストをする

# 概要
WindowsformのUIを含めたテスト方法の導入方法を調べたので忘備録として残しておきます。

# 実現したいことと対処方法
Windows Formの結合テストをしたい
→Windows Application Driverと Seleniumプラグインを使って実現する



# 開発環境
名称|バージョン|説明
---|----------|----
Windows|10|OS
VisualStudio|Community 2022| IDE
.Net FrameWork|4.8|WindowsFormのフレームワーク
Windows Application Driver|1.2.99|WindowsデスクトップアプリケーションのUIテストを自動化するためのツール
# NuGet関係のパッケージ


名称|バージョン|説明
---|----------|----
TestContainers|3.3.0|データアクセス層のテストコンテナライブラリ
TestContainers.PostgreSql|3.3.0|TestContainersのPostgresqlインスタンス
xUnit|2.9.3|C#のユニットテストのフレームワーク
xunit.runner.msbuild|2.9.3|xUnitの実行環境
xunit.runner.visualstudio|3.1.0|xUnitの実行環境(visual studioのテストエクスプローラー)
Selenium.Support|3.8.0
Selenium.WEbDriver|3.8.0

# 手順

## Windows Application Driverのインストール
https://github.com/Microsoft/WinAppDriver/releases
のAssetsから　
WindowsApplicationDriver-1.2.99-win-arm64.exe
をインストールする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2710623/dfb4bc95-8963-45e4-b11b-f5707b32dfed.png)

インストール後、
"C:\Program Files\Windows Application Driver"が作成されるのを確認できるので、
WinAppDriver.exeを管理者権限で実行する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2710623/6f438454-377f-4690-a412-8d875b2bdf07.png)



## 自作のwindows Formをテスト


### Nugetでパッケージのインストール

### Form作成
ボタンを押すと　テキストボックスにHello Worldが表示されるアプリケーションです。
```csharp:Form1.cs
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace WindowsForm_sample
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            textBox1.Text = "Hello World";
        }
    }
}


```
Formの画面
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2710623/25cd4509-6cae-4db4-be82-6c5b50ecfa6e.png)


### テストコード


```csharp:FormSession.cs
using Microsoft.VisualStudio.TestTools.UnitTesting;
using OpenQA.Selenium.Appium.Windows;
using OpenQA.Selenium.Remote;
using OpenQA.Selenium;
using Microsoft.ServiceBus.Configuration;
using System;
using System.IO;

namespace UITestSample.Test
{
    // 初期設定、最後の後処理をするクラス  
    // シナリオテストの継承元のクラス  
    public class FormSession
    {
        protected const string WindowsApplicationDriverUrl = "http://127.0.0.1:4723";
        private static readonly string NotepadAppId = Path.Combine(Environment.CurrentDirectory, "WindowsForm_sample.exe");
        protected static WindowsDriver<OpenQA.Selenium.Appium.Windows.WindowsElement> session;
        protected static OpenQA.Selenium.Appium.Windows.WindowsElement editBox;

        public static void Setup(TestContext context)
        {
            if (session == null)
            {
                DesiredCapabilities appCapabilities = new OpenQA.Selenium.Remote.DesiredCapabilities();
                appCapabilities.SetCapability("app", NotepadAppId);
                session = new WindowsDriver<OpenQA.Selenium.Appium.Windows.WindowsElement>(new Uri(WindowsApplicationDriverUrl), appCapabilities);
                Assert.AreEqual("Form1", session.Title);
            }
        }

        // セッションを切って　アプリケーションを閉じる  
        public static void TearDown()
        {
            // Close the application and delete the session  
            if (session != null)
            {
                session.Close();
                session.Quit();
                session = null;
            }
        }
    }
}

```


```csharp:ScenarioTest.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace UITestSample.Test
{
    [TestClass]
    public class ScenarioTest : FormSession
    {
        [TestMethod]
        public void ボタンを押すとHelloWorlが表示される()
        {
            Thread.Sleep(TimeSpan.FromSeconds(2));
            session.FindElementByName("button1").Click();
            string result = session.FindElementByAccessibilityId("textBox1").Text;
            Assert.AreEqual("Hello World", result);
        }

        [ClassInitialize]
        public static void ClassInitialize(TestContext context)
        {
            Setup(context);
        }

        [ClassCleanup]
        public static void ClassCleanup()
        {
            TearDown();
        }

    }
}



```

### テスト実行結果
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2710623/b03b7861-9214-41d8-aa3b-bec6ef4a9722.png)










# 課題
データベースにアクセスしてテストができるか。
TestContainersと組み合わせることができるか。



# 感想


現実務に使えるかは微妙ですね。工数足りないから　提案するのは難しそうです。
品質への意識が高く、リグレッションテストを積極的にするというプロジェクトなら活用できると思いました。


# 手間取った点
Selenium.WebDriverのバージョンによって書き方が異なる。
最新版(4.33.0)とgithubのサンプルのバージョン(3.8.0)で書きっぷりが違いました。最新版の書き方を調べるのが面倒だったので3.8.0に下げて対処しました。
# 参考

## 公式

https://learn.microsoft.com/ja-jp/visualstudio/test/use-ui-automation-to-test-your-code?view=vs-2022

## github WinAppDriverをインストール
https://github.com/Microsoft/WinAppDriver

## 公式で参考にしたプロジェクト
https://github.com/microsoft/WinAppDriver/tree/v1.0/Samples/C%23/NotepadTest

## Windows Application Driverのインストール方法

https://qiita.com/yuuhu04/items/5a96608ad96eccee34a0

## github コミット分

https://github.com/RYA234/WindowsForm_sample/commit/982a921b86e971f5c15ccd930ff6bf151c2b3a69