an SE diary

2011-05-16

[][][]NunitFormsサンプル

テストの自動化は今では割と当たり前になってきていると思いますが、GUIのテストとなるとやはり敷居が高い面もあるかと思います。

WebであればSeleniumなどいくつかツールがあるようですが、業務アプリ中心となるWindows.FormsについてはGUIテストはどう書けばよいでしょうか。

デモなどでVS2010の自動テスト機能などをみていると(使ったことはないですが)使い勝手はよさそうかな、なんて思いますが、それを使わなくてもNUnitFormsを使えばWindows.FormsのGUIテストは簡単に書けますよー、ということで以下サンプルです。

自分も昔の知識のままで使っていたところもあったのでそのへんの確認の意味も含めて。

(たとえばMessageBox表示などは、回避する方向でテスト自動化していた)



さて、Nunitformsですが、プロジェクトページ(http://nunitforms.sourceforge.net/index.html)から「Download」でダウンロードページにいって、SourceForgeのリンクをたどると、

http://sourceforge.net/projects/nunitforms/files/nunitforms/

ここに飛んで、「おいおい、最新版は2006年じゃねえか、こんなメンテナンスされていないもの使えるかー  (ノ`Д´)ノ彡┻━┻」となり、あえなく採用されないケースもあるかと思います。


ただ、ここから上部メニュー「Code」→「SVN」を選んで、リポジトリ情報のページに飛んで、「Browse Subversion Repository」をクリックしてみてください。

すると、5/5現在で、Last Log Entryに「Updated nunit (from version 2.5.9) to version 2.5.10.」とでてきます。

何気に、最新版のNunit対応しているんですね!

trunkをたどってみると、libのNunitバージョンが更新されているみたい。

sourceはそこまで直近ではないですが、8ヶ月前に更新があります。

なので、まだメンテナンスされているライブラリであるといえるでしょう。



前提として、VS2010 Expressインストール済であることとします。

また、Nunitインストールして置いてください。(現時点の最新版は、2.5.10)


VS2010 Express、Nunit導入についてはTDD.Netが分かりやすいです。

http://www.tdd-net.jp/

あ、VS2010についてちょっと自分ではまったところの注意点を。。。

VS2010 Expressだと初期状態では構成マネージャが出てきません。

 ツール→オプション

 プロジェクトおよびソリューション

  すべての設定を表示 にチェック

  ビルド構成の詳細を表示 にチェック

 ツール→設定→上級者設定にチェック

とすることでビルドメニューが出てきて、構成マネージャが選択可能となります。


NunitはNunitFormsのソースに付属のものを使う。


1.Nunitformsの最新ソース取得&ビルド

まずは、先ほどのSourceforgeから最新ソースを取得してビルドします。

SVNクライアントはtortoiesSVNなどでいいでしょう。(というかこれしか知らない)


落としてきたら、nunitformsフォルダのtest.batをたたけばNantビルドされてdllができるかと思いきや、どうも出来ない(なぜだー!!)ようなので、sourceフォルダのNUnitForms.slnファイルを開きます。

そしてビルドした後に、Nunitを起動して、NUnitForms.Test\bin\ReleaseにあるNUnitForms.Test.dllを選択してテストを実行します。

すると、GUIのてすとがだーーーーっと動いて、途中黄色になり、一部赤くなります。(-.-)なんでだ。。。

ですが、これで一応ビルドされました。

細かいことは気にせず、作成されたNUnitForms.dllを使って、これからサンプルを作ります。


2.ソリューション&サンプルプロジェクト&サンプルテストプロジェクト作成

期待動作としては以下の3点を想定してテストします。

・「Helloと表示」ボタンクリックでフォーム上のラベルに「Hello」と表示されること。

・「MessageBoxにHelloと表示」ボタンクリックで、メッセージボックスに「Hello」と表示されること

・「別画面にHelloと表示」ボタンクリックで、別のモーダルフォームのラベルに「Hello」と表示されること

プロジェクト構成は以下です。

f:id:masakitk:20110518010105j:image

NunitFormsSampleソリューション
├NunitFormsSampleプロジェクト
│├ModalSampleForm.cs
│├Program.cs
│└SampleForm.cs
└NunitFormsSampleTestプロジェクト
 └SampleFormTest.cs

各ソースファイルの内容は、

Program.cs

using System;
using System.Windows.Forms;

namespace NunitFormsSample
{
    static class Program
    {
        /// <summary>
        /// アプリケーションのメイン エントリ ポイントです。
        /// </summary>
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new メインフォーム());
        }
    }
}

SampleForm.cs

適当なデザインで

・Label:ハローラベル

・Button:ハローボタン

・Button:メッセージボックスボタン

・Button:別画面表示ボタン

を配置し、ButtonについてはClickイベントを設定してください。

(※Nameプロパティに上記日本語名を設定してください)

f:id:masakitk:20110516204536j:image

using System;
using System.Windows.Forms;

namespace NunitFormsSample
{
    public partial class メインフォーム : Form
    {
        public メインフォーム()
        {
            InitializeComponent();
        }

        private void ハローボタン_Click(object sender, EventArgs e)
        {
            this.ハローラベル.Text = "Hello";
        }

        private void メッセージボックスボタン_Click(object sender, EventArgs e)
        {
            MessageBox.Show("Hello", "メッセージ");
        }

        private void 別画面表示ボタン_Click(object sender, EventArgs e)
        {
            new モーダルサンプルフォーム().ShowDialog();
        }
    }
}

ModalSampleForm.cs

適当なデザインで

・Label:メッセージ用ラベル

・Button:閉じるボタン

を配置し、ButtonについてはClickイベントを設定してください。

(※Nameプロパティに上記日本語名を設定してください)

f:id:masakitk:20110516204538j:image

using System;
using System.Windows.Forms;

namespace NunitFormsSample
{
    public partial class モーダルサンプルフォーム : Form
    {
        public モーダルサンプルフォーム()
        {
            InitializeComponent();
        }

        private void 閉じるボタン_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        private void モーダルサンプルフォーム_Load(object sender, EventArgs e)
        {
            this.メッセージ用ラベル.Text = "Hello";
        }
    }
}

そしてここが肝心のテストコード。

SampleFormTest.cs

using System;
using NUnit.Extensions.Forms;
using NUnit.Framework;
using NunitFormsSample;
using System.Windows.Forms;

namespace NunitFormsSampleTest
{
    public class SampleFormTest : NUnitFormTest
    {
        private メインフォーム テスト対象画面;

        public override void Setup()
        {
            base.Setup();
            テスト対象画面 = new メインフォーム();
            テスト対象画面.Show();
        }

        public override void TearDown()
        {
            画面が開いていたら閉じる(typeof(メインフォーム));
            base.TearDown();
        }

        private void 画面が開いていたら閉じる(Type type)
        {
            try
            {
                new FormFinder().Find(type.Name).Close();
            }
            catch (NoSuchControlException)
            {
                //画面がなければ問題なし! スルー
            }
        }

        [Test]
        public void Case01_サンプル画面にHelloと表示されること()
        {
            new ButtonTester("ハローボタン", テスト対象画面).Click();
            Assert.That(new Finder<Label>("ハローラベル").Find().Text, Is.EqualTo("Hello"));
        }

        [Test]
        public void Case02_メッセージボックスにHelloと表示されること()
        {
            ExpectModal("メッセージ", "Helloメッセージ表示確認");
            new ButtonTester("メッセージボックスボタン", テスト対象画面).Click();
        }
        
        public void Helloメッセージ表示確認()
        {
            Assert.That(new MessageBoxTester("メッセージ").Text, Is.EqualTo("Hello"));
            new MessageBoxTester("メッセージ").ClickOk();
        }

        [Test]
        public void Case03_モーダルフォームにHelloと表示されること()
        {
            ExpectModal("モーダルサンプルフォーム", "モーダル画面メッセージ表示確認");
            new ButtonTester("別画面表示ボタン", テスト対象画面).Click();
        }

        public void モーダル画面メッセージ表示確認()
        {
            Assert.That(new Finder<Label>("メッセージ用ラベル").Find().Text, Is.EqualTo("Hello"));
            new ButtonTester("閉じるボタン", "モーダルサンプルフォーム").Click();
        }
    }
}

キモはExpectModalですね。

Modalウィンドウが表示された際のテストについて、メソッド名を指定する形になります。

でもExpectModalが、古い形式との警告が出てしまいます。

警告は無視してはいけないので、推奨の形で書き直したいのですが、そこまで調べられていないので後日課題とします。

たぶん、匿名メソッドとかで華麗にかけるようになっているんだと思います。

メソッド名、ってちょっといけてないもんねー。


また、テストコードこそがテスト仕様書だ!!と言いたいので、コントロールを日本語名にしていたり、Assert.Thatを使っているけどちょっとさっきのExpectModalのあたりや、Finder.Find()のあたりが可読性がよくないなーとか思ったりしてます。課題です。


と、ここまで書いてきましたがNUnitFormsについてのサンプルは、猫背おやじさんのところが分かりやすいと思うので見るといいと思うよ!

http://d.hatena.ne.jp/nekozeoyaji/20100914/p1





9/5 追記

こんなふうに匿名メソッドで書けるようになってるのを、チームの人が見つけてくれました。かっちょいー。

        [Test]
        public void Case02_メッセージボックスにHelloと表示されること()
        {
            DialogBoxHandler = (タイトル, ウィンドウハンドル) =>
            {
                MessageBoxTester メッセージボックス = new MessageBoxTester(ウィンドウハンドル);
                Assert.That(タイトル, Is.EqualTo("メッセージ"));
                Assert.That(メッセージボックス.Text, Is.EqualTo("Hello"));
                メッセージボックス.ClickOk();
            };
            new ButtonTester("メッセージボックスボタン", テスト対象画面).Click();
        }

        [Test]
        public void Case03_モーダルフォームにHelloと表示されること()
        {
            ModalFormHandler = (タイトル, ウィンドウハンドル, フォーム) =>
            {
                Assert.That(new Finder<Label>("メッセージ用ラベル", フォーム).Find().Text, Is.EqualTo("Hello"));
                new ButtonTester("閉じるボタン", フォーム).Click();
            };
            new ButtonTester("別画面表示ボタン", テスト対象画面).Click();
        }

はてなユーザーのみコメントできます。はてなへログインもしくは新規登録をおこなってください。

Connection: close