連載
NAgileで始める実践アジャイル開発

第3回 ソフトウェアの良い設計を行うコツ

NAgiler 黒石 高広 & 小井土 亨
2006/02/25
Page1 Page2 Page3

2. テストファーストの基礎ツール

.NET開発においてテストファーストを実践するには、NUnitというオープンソースのテスティング・フレームワークを利用することが基本となる。

 NUnitについては、次に挙げているようにすでに多くの記事やWeb上の資料などで紹介されているので、そちらを参考にすればよい。

テスト駆動開発ツール最前線(後編) ― Test Driven .NETによる統合されたテスト

 また、NUnitとともに利用できるツールとして、Test Driven .NET(以下TD.NET)というオープンソースのツールがある。TD.NETは、NUnitなどのテスティング・フレームワークを呼び出し、Visual Studioの出力ウィンドウに結果を表示してくれる便利なツールだ。ちなみにVisual Studio 2005にも対応している。

ツールもいっぱいあるのですね、どれを使えばよいのですか?

   

NUnitを単体で使うか、TD.NETと組み合わせて使うかは、はっきりいって好みの問題だ。筆者は「NUnit-Gui」(=NUnitに付属する単体テスト用のWindowsアプリケーション)のグリーン・バーを見るのが好きなのでNUnitをメインで利用しているが(TD.NETではグリーン・バーは表示されない)、NUnit-Guiをデバッグのたびに起動せずに済むという理由でTD.NETを使っている開発者も多い。両方のツールを試してみて気に入った方を使うとよいだろう。

   

筆者って何ですか?

   

そんなことはどうでもよい。これらの基礎ツールは、主にビジネス・ロジックを記述したクラス・ライブラリのテストファーストを行うのに利用される。それもポイントの1つだな。

   

え……ちょっと待ってください。それじゃわたしの大好きなユーザー・インターフェイス(以下UI)層や、その次に好きなデータアクセス層ではテストファーストを実行できないってことですか?

   

そんなことはない。実はあまりよく知られていないが、UI層やデータアクセス層についてもNUnitを拡張したテスティング・フレームワークやテストファーストを可能にするSQL Server 2005の新機能などがあるのだ。今日はこれから、それらのツールや新機能を使ってUI層やデータアクセス層のテストファーストを実現する方法を教えよう。

3. UI層でのテストファースト

UI層は、その名のとおりユーザー・インターフェイスとなる層のことである。UIのWindows技術としては、大きくWindowsフォームとASP.NET Webフォームに分類することができる。今回はWindowsフォームでのテストファーストを例として取り上げ、NUnitFormsというオープンソースのツールを紹介する。

 NUnitFormsは、NUnitを拡張したWindowsフォーム用のテスティング・フレームワークである。NUnitと同様にテスト・コードとしてUIの振る舞いを記述でき、NUnit-Guiから実行することで視覚的にテスト結果を判断できるようになる。NUnitFormsは、次のページからダウンロードできる。

 インストールはここから最新バージョンのバイナリ版zipファイル(執筆時点では「NUnitForms-v1.3.1-bin.zip」)をダウンロードして、ローカル環境の任意の場所(例えば「C:\Program Files\NUnitForms-v1.3.1」)に解凍する。後は実際に使用する際に、「NUnitForms.dll」ファイルをアセンブリとして参照すればよい。併せて、同じフォルダの「nunit.framework.dll」ファイルもアセンブリとして参照する必要がある。

 今回は、次の画面のようなWindowsフォームをNUnitFormsを利用したテスト・コードの例とともに紹介する(なお、執筆時点でNUnitFormsは.NET Framework 2.0に対応していないため、本稿では.NET Framework 1.1でテスト・コードを記述している)。本稿で使用するサンプル・コード全体は次のリンク先からダウンロードできる。

テスティングを行うWindowsフォームの例(LoginForm.csのデザイン)
ユーザー名とパスワードを入力し、ログインを行うためのWindowsフォーム。[ログイン]ボタンをクリックすることでログイン処理が開始されるが、ユーザー名とパスワードが入力されていない状態で[ログイン]を実行すると、エラー・メッセージが表示される。
  フォームは、「LoginForm」というクラス名で作成し(ファイル名は「LoginForm.cs」)、タイトルのテキスト(Textプロパティ)は「ログイン画面」に変更する。
  [ユーザー名]テキストボックス。コントロール名は「txtUserName」、初期値(Textプロパティ)は「空文字列」、最大文字数(MaxLengthプロパティ)は「12」をそれぞれ指定する。
  [パスワード]テキストボックス。コントロール名は「txtPassword」、初期値(Textプロパティ)は「空文字列」、パスワード文字(PasswordCharプロパティ)は「*」、最大文字数(MaxLengthプロパティ)は「16」をそれぞれ指定する。
  [ログイン]ボタン。コントロール名は「btnLogin」、表示テキスト(Textプロパティ)は「ログイン」をそれぞれ指定する。[ログイン]ボタンのClickイベント・ハンドラを生成して、そこに[ユーザー名]/[パスワード]のテキストボックスの入力内容をチェックし、その内容がエラーに相当する場合には、[エラー・メッセージ表示]ラベルにエラー・メッセージを表示するコードを記述する。具体的な仕様は、ユーザー名が未入力の状態で[ログイン]がクリックされると[エラー・メッセージ表示]ラベルを「可視」に変更し(=VisibleプロパティをTrueに指定する)、そこに「ユーザー名を入力してください。」というテキストを表示する(=Textプロパティにテキストを設定する)。また、パスワードが未入力の状態で[ログイン]が実行されると、「可視」に変更し、「パスワードを入力してください。」というテキストを表示する。エラーがない場合には、ダイアログをそのまま閉じる。
  [エラーメッセージ表示]ラベル。コントロール名は「lblErrorMessage」、初期状態(Visibleプロパティ)は「不可視(False)」。

 上記のWindowsフォームに対するNUnitFormsを利用したテスト・コードは以下のようになる(ファイル名は「LoginFormTest.cs」)。なおNUnitFormsを利用するには、(前述のとおり)事前にNUnitFormsアセンブリとnunit.frameworkアセンブリへの参照が必要だ。

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

namespace WindowsApplication.Test
{
  [TestFixture]
  public class LoginFormTest : NUnitFormTest
  {
    Form loginForm;

    public override void Setup()
    {
      base.Setup ();
      loginForm = new LoginForm();
      loginForm.Show();
    }

    public override void TearDown()
    {
      loginForm.Close();
      base.TearDown ();
    }

    public override bool UseHidden
    {
      get
      {
        return false;
      }
    }

    [Test]
    public void ログインフォームのタイトル表示()
    {
      FormTester loginFormTester =
        new FormTester("LoginForm");
      Assert.AreEqual( "ログイン画面", loginFormTester.Text);
    }

    [Test]
    public void ユーザー名テキストボックスに設定されるべき値()
    {
      TextBoxTester userNameTester =
        new TextBoxTester("txtUserName");
      Assert.AreEqual(string.Empty, userNameTester.Text);
      Assert.AreEqual(12, userNameTester["MaxLength"]);
    }

    [Test]
    public void パスワードテキストボックスに設定されるべき値()
    {
      TextBoxTester passwordTester =
        new TextBoxTester("txtPassword");
      Assert.AreEqual(string.Empty, passwordTester.Text );
      Assert.AreEqual(16, passwordTester["MaxLength"]);
      Assert.AreEqual(char.Parse("*"),
        passwordTester["PasswordChar"]);
    }

    [Test]
    public void エラーメッセージラベルに設定されるべき値()
    {
      LabelTester errorMessageLabelTester =
        new LabelTester("lblErrorMessage");

      Assert.IsFalse(
        (bool)errorMessageLabelTester["Visible"]);
    }

    [Test]
    public void ユーザー名を入力しないとログインできない()
    {
      ButtonTester loginButtonTester =
        new ButtonTester("btnLogin");
      loginButtonTester.Click();
      LabelTester errorMessageLabelTester =
        new LabelTester("lblErrorMessage");
      Assert.IsTrue(
        (bool)errorMessageLabelTester["Visible"]);
      Assert.AreEqual( "ユーザー名を入力してください。",
        errorMessageLabelTester.Text);
    }

    [Test]
    public void パスワードも入力しないとログインできない()
    {
      TextBoxTester userNameTester =
        new TextBoxTester("txtUserName");
      Keyboard.UseOn( userNameTester );
      Keyboard.Click(Key.U);
      Keyboard.Click(Key.S);
      Keyboard.Click(Key.E);
      Keyboard.Click(Key.R);
      Keyboard.Click(Key.DIGIT_1);

      ButtonTester loginButtonTester =
        new ButtonTester("btnLogin");
      loginButtonTester.Click();
      LabelTester errorMessageLabelTester =
        new LabelTester("lblErrorMessage");
      Assert.IsTrue(
        (bool)errorMessageLabelTester["Visible"]);
      Assert.AreEqual("パスワードを入力してください。",
        errorMessageLabelTester.Text);
    }
  }
}
NUnitFormsを利用したテスト・コード(LoginFormTest.cs)
本稿のサンプル・コードでは、LoginFormクラスが「WindowsApplication」という名前空間に所属している。

 このようにNUnitFormsのコントロール・クラスを通じて、対応するUIのコントロールを制御できる。UI上のコントロールの値を取得するだけでなく、キーボードの制御やイベントの制御なども可能だ。

 以下は、NUnitFormsの実行結果だ。

NUnitFormsの実行結果(NUnit-Guiの実行画面)
NUnitに付属のNUnit-Guiアプリケーションを起動して、先ほど作成したテスト・コードを実行したところ。自動的にWindowsアプリケーションが起動され、テキストボックスなどに値が入力され、その実行結果が検証される。

 NUnitFormsの詳しい利用方法については、下記サイトにドキュメントとして公開されているので参考にしてほしい。

 また、今回はUI層の技術としてWindowsフォームを取り上げたが、Web UI技術であるASP.NET Webフォームでのテストファーストには、NUnitAspやVisual Studio 2005 Team SystemでのWebテストが利用できるので、興味がある方はそちらもぜひ試していただきたい。

すごい!! いろんなUIのテストができるんですね。よかった〜

   

まぁ落ち着け。UI層のテストは、テストファーストの中でも難しい領域の1つであることは間違いない。例えば、たとえNUnitFormsを利用したとしても、日本語入力の問題や、NUnitFormsがサポートしていないWindowsフォーム・コントロールをどうやってテストするかという問題が依然として残る。ツールの制限や解決領域を理解することも忘れずにおくことだ。

   
はい。世の中にはすべての問題を解決する<完ぺき>なツールは存在しないということですね。
   

そのとおり。いわゆる

「下手な鉄砲も数打ちゃ当たる」

じゃなかった、

「銀の弾丸は存在しない」

というやつだな。では続いてデータアクセス層でのテストファーストについて解説しよう。

 

 INDEX
  NAgileで始める実践アジャイル開発
  第3回 ソフトウェアの良い設計を行うコツ
    1.NAgileにおける設計のコツ「インクリメンタル設計」
  2.テストファーストの基礎ツール
    3.データアクセス層でのテストファースト
 
インデックス・ページヘ  「NAgileで始める実践アジャイル開発」


Insider.NET フォーラム 新着記事
  • 第2回 簡潔なコーディングのために (2017/7/26)
     ラムダ式で記述できるメンバの増加、throw式、out変数、タプルなど、C# 7には以前よりもコードを簡潔に記述できるような機能が導入されている
  • 第1回 Visual Studio Codeデバッグの基礎知識 (2017/7/21)
     Node.jsプログラムをデバッグしながら、Visual Studio Codeに統合されているデバッグ機能の基本の「キ」をマスターしよう
  • 第1回 明瞭なコーディングのために (2017/7/19)
     C# 7で追加された新機能の中から、「数値リテラル構文の改善」と「ローカル関数」を紹介する。これらは分かりやすいコードを記述するのに使える
  • Presentation Translator (2017/7/18)
     Presentation TranslatorはPowerPoint用のアドイン。プレゼンテーション時の字幕の付加や、多言語での質疑応答、スライドの翻訳を行える
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

注目のテーマ

Insider.NET 記事ランキング

本日 月間