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

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

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

■単体テストを準備/実施する

 これで、アプリケーション側のリポジトリ・クラス対応は完了だ。続いて、テスト・プロジェクト側でテストを準備/実施していこう。テスト・プロジェクト側で用意しなければならないのは、テスト用のリポジトリ・クラスと、テスト・クラス本体である。

[1]単体テスト用のリポジトリ・クラスを準備する

 データベースを準備しなくてもテストが実施できるよう、まずは単体テスト用のBooksTestRepositoryクラスを準備しておこう

using System;
using System.Collections.Generic;
using MvcTemplate.Models;

namespace MvcTemplate.Tests.Models
{
  class BooksTestRepository : IBooksRepository
  {

    public List<Book> GetAllBooks()
    {
      // ダミーのBookエンティティを生成し、リストとして返す
      var books = new List<Book>();

      for (var i = 0; i < 5; i++)
      {
        books.Add(
          new Book()
          {
            Isbn = "978-4-7980-3080-" + i.ToString(),
            Title = "書名" + i.ToString(),
            Price = 2000 + i,
            Publish = "出版社" + i.ToString(),
            Published = DateTime.Now.AddDays(i)
          }
        );
      }
      return books;
    }

    public Book CreateBook(Book bok)
    {
      // 何もせず、引数をそのまま返す
      return bok;
    }
  }
}
Public Class BooksTestRepository : Implements IBooksRepository

  Public Function GetAllBooks() As System.Collections.Generic.List(Of Book) Implements IBooksRepository.GetAllBooks

    ' ダミーのBookエンティティを生成し、リストとして返す
    Dim books = New List(Of Book)

    For i = 2 To 5
      books.Add(
        New Book() With {
          .Isbn = "978-4-7980-3080-" & i.ToString(),
          .Title = "書名" & i.ToString(),
          .Price = 2000 + i,
          .Publish = "出版社" & i.ToString(),
          .Published = DateTime.Now.AddDays(i)
        }
      )
    Next
    Return books
  End Function

  Public Function CreateBook(bok As Book) As Book Implements IBooksRepository.CreateBook
    ' 何もせず、引数をそのまま返す
    Return bok
  End Function
End Class
リスト11 単体テスト用の、ダミー・データを返すリポジトリ・クラス(上:BooksTestRepository.cs、下:BooksTestRepository.vb)

。BooksTestRepositoryクラスでは、前出のIBooksRepositoryインターフェイスを実装する必要がある。Indexメソッドはデータベースに接続する代わりに、ダミーのBookエンティティを返すだけのコードを、Createメソッドは引数に渡されたBookエンティティをそのまま返すだけのコードを、それぞれ準備する。

[2]テスト・コードを準備する

 これで、コントローラをテストするための準備が整ったので、いよいよテスト・メソッドを記述する。

using System;
using System.Collections.Generic;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using MvcTemplate.Controllers;
using MvcTemplate.Tests.Models;
using System.Web.Mvc;
using MvcTemplate.Models;

[TestMethod]
public void Index()
{
  // アクションを実行
  var ctrl = this.GetController();
  var result = ctrl.Index() as ViewResult;

  // 結果の検証
  Assert.AreEqual(5, ((List<Book>)result.Model).Count);
}

[TestMethod]
public void Create()
{
  // アクションを実行
  var ctrl = this.GetController();
  var result = ctrl.Create(
      new Book()
      {
        Isbn = "978-4-7980-3080-0",
        Title = "書名",
        Price = 2000,
        Publish = "出版社",
        Published = DateTime.Now
      }
    );

  // 結果の検証
  Assert.IsInstanceOfType(result, typeof(RedirectToRouteResult));
}

private BooksController GetController()
{
  // テスト用のリポジトリ・クラスを、コントローラにセット
  return new BooksController(
    new BooksTestRepository());

}
Imports MvcTemplateVb.MvcTemplateVb
Imports System.Web.Mvc

<TestMethod()>
Public Sub Index()

  ' アクションを実行
  Dim ctrl = Me.GetController()
  Dim result = DirectCast(ctrl.Index(), ViewResult)

  ' 結果の検証
  Assert.AreEqual(5, DirectCast(result.Model, List(Of Book)).Count)
End Sub

<TestMethod()>
Public Sub Create()

  ' アクションを実行
  Dim ctrl = Me.GetController()
  Dim result = ctrl.Create(
    New Book() With {
      .Isbn = "978-4-7980-3080-0",
      .Title = "書名",
      .Price = 2000,
      .Publish = "出版社",
      .Published = DateTime.Now
    }
  )

  ' 結果の検証
  Assert.IsInstanceOfType(result, GetType(RedirectToRouteResult))
End Sub

Private Function GetController() As BooksController
  ' テスト用のリポジトリ・クラスを、コントローラにセット
  Return New BooksController(
    New BooksTestRepository())

End Function
リスト12 リポジトリ・クラスを介したアクションをテストするコード(上:BooksControllerTest.cs、下:BooksControllerTest.vb)

 テスト用のリポジトリ・クラスを適用するには、コントローラ・クラスのコンストラクタに、引数としてテスト・リポジトリを渡すだけだ(太字部分)。

 後は、先にも示したように、アクション・メソッドを呼び出し、その結果をAssertクラスで検証するだけでよい。Indexテスト・メソッドでは、Indexアクションで得られたモデル(リスト)が5個のエンティティを含んでいることを、Createテスト・メソッドでは、Createアクションの結果、RedirectToRouteResultクラスが返されることを、それぞれチェックしている。

 以上、今回はアプリケーションをテストする方法、モック・ライブラリMoqの基本、そして、データベース連携アプリケーションのテストを容易にする定石でもあるリポジトリ・クラスについて解説した。実践的なアプリケーションでは、あまたのコードが登場するが、まずは本稿で紹介したアプローチを理解しておけば、ほぼ同じ要領でテストを実施できるはずだ。

 さて、本連載もこの回で最終回。ASP.NET MVCには、ここで紹介したほかにもさまざまな機能が含まれているが、まずは、本連載で紹介した機能を理解できていれば、基本的なアプリケーションは開発できるようになっているはずだ。前回の連載も併せてこの連載が、読者諸兄にとってASP.NET MVCを学習する手掛かりとなれば幸いである。End of Article

 

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

本日 月間