Webのユニットテスト② .NET
前回の続きです。
Default.aspxのテストを簡単にする為にユーティリティクラスを作ってみます。
WebアプリケーションのテストはSeleniumを使ってテストしてみます。
Selenium RCは.NETにも対応しているので、Javaで作ったクラスを.NETに移植していきます。
WebTester.cs
SeleniumServerを起動し、Seleniumインスタンスを生成します。
Seleniumインスタンスを使って、ブラウザを操作しながらテストしていきます。
using System; using System.Configuration; using System.Diagnostics; using Selenium; namespace WebAndNDbUnitSampleTest { public class WebTester { private ISelenium selenium; private string className; private string methodName; public void SetUp() { // テスト対象のサーバURL&ブラウザ設定をApp.configから読み込む string url = ConfigurationManager.AppSettings["SeleniumTest.Url"]; string browser = ConfigurationManager.AppSettings["SeleniumTest.Browser"]; // seleniumインスタンス起動 this.selenium = new DefaultSelenium("localhost", 4444, browser, url); this.selenium.Start(); } public void TearDown() { // 画面のスクリーンショットを保存 CaptureScreenshot(); // Seleniumインスタンスを停止 this.selenium.Close(); this.selenium.Stop(); } public ISelenium GetSelenium() { return this.selenium; } public void Open(String url) { // アプリケーション名の取得 string appName = ConfigurationManager.AppSettings["SeleniumTest.App"]; // ブラウザを最大化で表示 this.selenium.Open(appName + url); this.selenium.WindowMaximize(); // 呼び出し側のクラス名&メソッド名を保持しておく StackTrace st = new StackTrace(true); this.className = st.GetFrame(2).GetFileName(); this.methodName = st.GetFrame(2).GetMethod().Name; } public void CaptureScreenshot() { CaptureScreenshot(this.className + "." + this.methodName + ".png"); } public void CaptureScreenshot(String fileName) { // スクリーンショット保存ディレクトリが指定されている場合に、スクリーンショットを保存する string ScreenshotDir = ConfigurationManager.AppSettings["SeleniumTest.ScreenshotDir"]; if (ScreenshotDir != null) { // 画面のスクリーンショットを保存 this.selenium.CaptureScreenshot(ScreenshotDir + "/" + fileName); } } } }
App.config
WebTesterで使用するプロパティを定義しています。
他のブラウザでのテストも簡単に行えるように、定義情報を外だしにしておきます。
<?xml version="1.0" encoding="utf-8" ?> <configuration> <appSettings> <!-- テスト対象サーバのURL --> <add key="SeleniumTest.Url" value="http://localhost:8080/" /> <!-- テスト対象のWEBアプリケーション名 --> <add key="SeleniumTest.App" value="" /> <!-- テストで使用するブラウザ --> <add key="SeleniumTest.Browser" value="*iexplore" /> </appSettings> <connectionStrings> <add name="DataBase" connectionString="Server=XXXXX\SQLEXPRESS;Initial Catalog=sample;User ID=sa;Password=hogehoge;" providerName="System.Data.SqlClient"/> </connectionStrings> </configuration>
HtmlTableAssert.cs
指定されたHTMLテーブルの行数、列数、表示値をアサートするクラスです。
Seleniumにありそうなクラスですが、ないみたいなので作ってみました。
SeleniumではHTMLの要素をXPATHで指定します。
例えば、class名がitsというtableの1行2列目にある要素を指定したい場合は、
xpath=//table[@class='its']//tr[1]/td[2]
となります。
using System; using NUnit.Framework; using Selenium; namespace WebAndNDbUnitSampleTest { class HtmlTableAssert { private HtmlTableAssert() { } // テーブルの表示データを確認 public static void AssertEquals(ISelenium selenium, string tablePath, string[][] expected) { for (int i = 0; i < expected.GetLength(0); i++) { // 比較対象の行が存在するか if (!selenium.IsElementPresent(GetRow(tablePath, i))) { Assert.Fail("Different number of Rows : " + expected.GetLength(0) + " : " + (i + 1)); } for (int j = 0; j < expected[i].GetLength(0); j++) { // 比較対象の列が存在するか if (!selenium.IsElementPresent(GetColumn(tablePath, i, j))) { Assert.Fail("Different number of columns : " + expected[i].GetLength(0) + " : " + (j + 1)); } // 列の表示値を確認 string actual = selenium.GetText(GetColumn(tablePath, i, j)); Assert.AreEqual(expected[i][j], actual, "Difference on row:" + (i + 1) + ", column:" + expected[i][j]); } // 比較対象の列数が期待値を超えていないか if (selenium.IsElementPresent(GetColumn(tablePath, i, expected[i].GetLength(0)))) { Assert.Fail("Over number of columns : " + expected[i].GetLength(0)); } } // 比較対象の行数が期待値を超えていないか if (selenium.IsElementPresent(GetRow(tablePath, expected.GetLength(0)))) { Assert.Fail("Over number of rows : " + expected.GetLength(0)); } } private static string GetRow(String tablePath, int row) { //return "xpath=//" + tablePath + "//tr[" + (row + 1) + "]"; return "xpath=//" + tablePath + "//tr[" + (row + 2) + "]"; // ヘッダ行は対象外 } private static string GetColumn(String tablePath, int row, int column) { return GetRow(tablePath, row) + "/td[" + (column + 1) + "]"; } } }