ASP.NET MVC アプリの画面テストで Selenium を試してみた

Selenium 実践入門を読んで Selenium 熱に火がついたので、 ASP.NET MVC で実装しているアプリの画面テストを Selenium 使って書くことにした。 もちろん C# で。

画面テスト専用のテストプロジェクトを作成し、 Selenium を使うためのパッケージをインストール。

PM> Install-Package Selenium.WebDriver
PM> Install-Package Selenium.Support

最初はログインページの自動テストから書くことする。 ページオブジェクトパターンでやるので、ログインページを抽象化したページオブジェクトを作っておく。

using OpenQA.Selenium;

namespace MyMvcApp.UITests
{
    public class LoginPage
    {
        private IWebDriver _driver;

        public LoginPage(IWebDriver driver)
        {
            _driver = driver;
        }

        private IWebElement UserName => _driver.FindElement(By.Name("UserName"));

        private IWebElement Password => _driver.FindElement(By.Name("Password"));

        private IWebElement Submit => _driver.FindElement(By.CssSelector("input[type=submit]"));

        public void SetUserName(string userName)
        {
            UserName.Clear();
            UserName.SendKeys(userName);
        }

        public void SetPassword(string password)
        {
            Password.Clear();
            Password.SendKeys(password);
        }

        public void ClearAll()
        {
            UserName.Clear();
            Password.Clear();
        }

        public string GetValidationErrorMessage()
        {
            // 検証エラーメッセージは Bootstrap の Alert を使って表示する
            var alert = _driver.FindElement(By.CssSelector("div.alert-danger"));
            return alert.Text;
        }

        // 成功したらダッシュボードに移動する
        // DashboardPage は省略
        public DashboardPage Signin()
        {
            Submit.Submit();
            return new DashboardPage(_driver);
        }

        public LoginPage SigninInExceptingFailer()
        {
            Submit.Submit();
            return new LoginPage(_driver);
        }
    }
}

Selenium を使った画面テストを、このページオブジェクトを使って書いてみた。

using Microsoft.VisualStudio.TestTools.UnitTesting;
using OpenQA.Selenium;
using OpenQA.Selenium.Firefox;

namespace MyMvcApp.UITests
{
    [TestClass]
    public class LoginTest
    {
        private const string LoginUrl = "http://localhost:49424/signin";

        private IWebDriver _driver;

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

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

        [TestMethod]
        public void ユーザー名とパスワードが正しいときログインできる()
        {
            _driver.Navigate().GoToUrl(LoginUrl);
            var page = new LoginPage(_driver);
            page.SetUserName("admin");
            page.SetPassword("1234admin");
            var nextPage = page.Signin();

            Assert.AreEquals("ダッシュボード", _driver.Title);
        }

        [TestMethod]
        public void ユーザー名が間違っているときログインできない()
        {
            _driver.Navigate().GoToUrl(LoginUrl);
            var page = new LoginPage(_driver);
            page.SetUserName("dummy_user");
            page.SetPassword("123admin");
            var nextPage = page.SigninInExceptingFailer();

            StringAssert.Contains(nextPage.GetValidationErrorMessage(), "ユーザー名");
        }

        [TestMethod]
        public void パスワードが間違っているときログインできない()
        {
            _driver.Navigate().GoToUrl(LoginUrl);
            var page = new LoginPage(_driver);
            page.SetUserName("admin");
            page.SetPassword("dummy_password");
            var nextPage = page.SigninInExceptingFailer();

            StringAssert.Contains(nextPage.GetValidationErrorMessage(), "パスワード");
        }
    }
}

テスト対象の ASP.NET MVC アプリをあらかじめ実行しておいて、テストを実行したところ上手くいった。 ただ、テスト対象の ASP.NET MVC アプリを毎回手動で起動しておくのは面倒なので、なんとか自動化できないものか。

あと、テストデータの投入もどうしようか悩む。テスト用に Web API を用意するか、直接データベースに投入するか。 直接データベースに投入した方が速いから、今のところそれでいこうかと検討中。 他にいい案があればいいんだけど。