連載:ASP.NET MVC入門【バージョン3対応】

最終回 テスト自動化でアプリケーションの品質向上

山田 祥寛(http://www.wings.msn.to/
2011/11/24
Page1 Page2 Page3 Page4

 アプリケーションをModel−View−Controllerと明確に分離することには、単体テスト(=ユニット・テスト)を行いやすくするという目的もある。

 例えばWebフォームでは、すべての機能がページに集約されるので、単体テストを実施するにはページをインスタンス化するためにWebサーバを準備する必要があった。しかしASP.NET MVCでは、例えばControllerを表すコントローラ・クラスも、POCO(Plain Old CLR Object)であるので、インスタンス化も容易だ。テスト実施に当たってサーバの準備は必要ない。これは、ASP.NET MVCの大きな特長の1つだ。

 連載最終回となる今回は、これまで作成したサンプルを前提に、ASP.NET MVCアプリケーションをテストする方法について、以下の内容を軸に解説する。

  • Visual Studioで単体テストを準備/実行する方法
  • モック定義のためのMoqライブラリの用法
  • データ・アクセスのコードを集約するリポジトリ・クラスの記述

 それではさっそく、始めよう。

単体テストの基本を理解する

 テスト・プロジェクトを作成するには、「ASP.NET MVC 3 Web アプリケーション」プロジェクトを作成する際に[新しいASP.NET MVC 3プロジェクト]ダイアログで、[単体テスト プロジェクトを作成する]をチェックするだけだ。プロジェクト名は、デフォルトで、「<元のプロジェクト名>.Tests」、使用するテスト・フレームワークはVisual Studio標準の「Visual Studio Unit Test」となる。別にインストールすることで、NUnitのようなテスト・フレームワークを利用することも可能だ。

 なお、テスト機能は、Visual Web Developer Express Edition(以降、VWD)では標準搭載されていないので、テスト・プロジェクトもVWDでは作成できない。


図1 [新しいASP.NET MVC 3プロジェクト]ダイアログ
[単体テスト プロジェクトを作成する]をチェックするだけでテスト用のプロジェクトも作成できる。

 以下では、まず「基本的な単体テストの手順を確認する」という意味で、第1回で作成したHello#Indexアクションをテストしてみよう。

[1]テスト・クラスを追加する

 テスト・クラスを追加するには、ソリューション・エクスプローラからテスト・プロジェクトのControllersフォルダを右クリックし、コンテキスト・メニューから[追加]−[新しいテスト]を選択すればよい。[新しいテストの追加]ダイアログが表示されるので、以下の図の要領でテスト・クラスを作成しよう。


図2 [新しいテストの追加]ダイアログ

[2]テスト・メソッドを作成する

 [OK]ボタンをクリックすると、テスト・クラスの骨組みが自動生成されるので、以下のようにテスト・メソッドを追加する。

using Microsoft.VisualStudio.TestTools.UnitTesting;
using MvcTemplate.Controllers;
using System.Web.Mvc;

……中略……

[TestMethod]
public void Index()
{
  // Hello#Indexアクションを実行
  var con = new HelloController();
  var result = con.Index() as ViewResult;

  // Assertクラスで結果を検証
  Assert.AreEqual("こんにちは、世界!", result.ViewBag.Message);
  Assert.AreEqual("", result.ViewName);
}
Imports MvcTemplateVb.MvcTemplateVb
Imports System.Web.Mvc

……中略……

<TestMethod()>
Public Sub Index()

  ' Hello#Indexアクションを実行
  Dim con = New HelloController()
  Dim result = DirectCast(con.Index(), ViewResult)

  ' Assertクラスで結果を検証
  Assert.AreEqual("こんにちは、世界!", result.ViewBag.Message)
  Assert.AreEqual("", result.ViewName)
End Sub
リスト1 Hello#Indexアクションをテストするためのコード(上:HelloControllerTest.cs、下:HelloControllerTest.vb)

 テスト・メソッドであることを表すには、メソッド宣言にTestMethod属性(Microsoft.VisualStudio.TestTools.UnitTesting名前空間)を付与するだけでよい(太字)。

 テスト・メソッドの中では、Helloコントローラのインスタンスを生成し、アクション・メソッドを実行している( )。アクション・メソッドの戻り値はActionResultオブジェクトであるので、結果を適切な型にキャストするのを忘れないこと。

 後は、Assertクラスでアクションにより得られた結果を確認するだけだ( )。Assertクラスは、テストで得られた結果の正否をチェックするためのクラスで、例えばAreEqualメソッドを利用することで、第2引数(実際値)が第1引数(期待値)と等しいかどうかを判定できる。サンプルのチェック内容は、以下のとおりである。

  • ビュー変数Messageが「こんにちは、世界!」に等しいか
  • ビュー名(result.ViewName)が空であるか

 ビュー名はIndexではなく、空文字列である点に注意してほしい。ビュー名が指定されない場合、アクションと同名のビューが呼び出されるというのは、ViewResultクラスの内部的な挙動に過ぎず、ビュー名(ViewNameプロパティ)そのものはあくまで空となる。

 そのほか、Assertクラスで提供されるメソッドについては、「Microsoft.VisualStudio.TestTools.UnitTesting名前空間」も参照されたい。最も基本的なAssertクラスのほか、文字列やコレクションを判定するためのStringAssert/CollectionAssertクラスなども用意されている。

[3]テスト・メソッドを実行する

 テストを実行するには、テスト・メソッドのブロック内で右クリックし、コンテキスト・メニューから[テストの実行]を選択すればよい。テストに成功すると、[テスト結果]ウィンドウに以下のような結果が表示される。


図3 [テスト結果]ウィンドウ(成功した場合)

 試しに、先ほどのテスト・メソッドを以下のように書き換えてみると、テストは失敗するはずだ。

Assert.AreEqual("こんにちは、世界!", result.ViewBag.Message)
リスト2 失敗するテスト・コード

 果たして、テストを再実行すると、今度は[テスト結果]ウィンドウにはテストが失敗したことを示す赤いアイコンが表示される。該当の行をクリックすると、メイン・ウィンドウからテスト失敗の理由も確認できる。


図4 [テスト結果]ウィンドウ(失敗した場合)

 

 INDEX
  ASP.NET MVC入門【バージョン3対応】
  最終回 テスト自動化でアプリケーションの品質向上
  1.単体テストの基本を理解する
    2.モック・ライブラリMoqの利用方法
    3.データベース・アクセスを伴うテスト(1)
    4.データベース・アクセスを伴うテスト(2)
 
インデックス・ページヘ  「ASP.NET MVC入門【バージョン3対応】」


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 記事ランキング

本日 月間