Selenium を使った画面テストでテスト対象の ASP.NET MVC アプリを自動起動する

ASP.NET MVC で開発しているアプリの画面テストを、Selenium を使って書き始めた。

tnakamura.hatenablog.com

テストを実行するときは、先に ASP.NET MVC アプリを Visual Studio から実行しないといけない。 毎回これやるの面倒なんで、IIS Express を使って自動化してみた。

using Microsoft.VisualStudio.TestTools.UnitTesting;
using OpenQA.Selenium;
using OpenQA.Selenium.Firefox;
using System;
using System.Diagnostics;
using System.IO;

namespace MyMvcApp.UITests
{
    /// <summary>
    /// Selenium WebDriver を使った画面テストに共通する機能を提供します。
    /// </summary>
    [TestClass]
    public abstract class SeleniumTest
    {
        /// <summary>
        /// WEB ブラウザのドライバーを取得します。
        /// </summary>
        protected IWebDriver Driver { get; private set; }

        /// <summary>
        /// IIS のポート
        /// </summary>
        private const int Port = 2020;

        /// <summary>
        /// ベースアドレス
        /// </summary>
        protected static readonly string BaseAddress = $"http://localhost:{Port}";

        [TestInitialize]
        public virtual void TestInitialize()
        {
            Driver = new FirefoxDriver();
        }

        [TestCleanup]
        public virtual void TestCleanup()
        {
            Driver.Quit();
        }

        /// <summary>
        /// IIS Express のプロセス
        /// </summary>
        private static Process _iisProcess;

        /// <summary>
        /// IIS Express を開始します。
        /// </summary>
        private static void StartIIS()
        {
            if (_iisProcess == null)
            {
                var applicationPath = GetApplicationPath("MyMvcApp");
                var programFiles = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles);
                var iisPath = Path.Combine(programFiles, "IIS Express", "iisexpress.exe");
                var startInfo = new ProcessStartInfo
                {
                    FileName = iisPath,
                    Arguments = $"/path:\"{applicationPath}\" /port:{Port}",
                };
                _iisProcess = Process.Start(startInfo);
            }
        }

        /// <summary>
        /// ソリューションフォルダ直下にあるテスト対象アプリのフォルダパスを取得します。
        /// </summary>
        /// <returns>テスト対象アプリのフォルダパス</returns>
        private static string GetApplicationPath(string applicationName)
        {
            var solutionFolder = Path.GetDirectoryName(
                Path.GetDirectoryName(
                    Path.GetDirectoryName(AppDomain.CurrentDomain.BaseDirectory)));
            return Path.Combine(solutionFolder, applicationName);
        }

        /// <summary>
        /// IIS Express を停止します。
        /// </summary>
        private static void StopIIS()
        {
            if (_iisProcess != null &&
                _iisProcess.HasExited == false)
            {
                _iisProcess.Kill();
            }
        }

        [AssemblyInitialize]
        public static void AssemblyInitialize(TestContext testContext)
        {
            StartIIS();
        }

        [AssemblyCleanup]
        public static void AssemblyCleanup()
        {
            StopIIS();
        }
    }
}

Proess クラスを使って、テスト対象の ASP.NET MVC アプリを IIS Express で起動している。 IIS Express の起動処理はテスト実行時に1回だけやればいいので、AssemblyInitialize 属性を付けた初期化用メソッドの中で呼び出している。

あとは、このクラスを継承してテストクラスを作ればいい。