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

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

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

データベース・アクセスを伴うテスト

 ここまでは説明を簡単化するために、アクション・メソッドに直接、データベース・アクセスのロジックを記述してきた。しかし、Model−View−Controllerの本来の考え方からすれば、Controllerの役割は、

  • リクエスト・データの処理
  • モデルの呼び出し
  • 結果のビューへの引き渡し

に限定すべきであり、データ・アクセスのコードが混在するのは望ましくない。データ・アクセスのコードはアクション・メソッドを複雑にするだけでなく、単体テストを難しくする原因にもなるためだ(テストのために、データベースを準備しなければならない)。

 そこで登場するのが、リポジトリ・クラスだ。リポジトリ・クラスは、Repository(集積)という名前からも想像できるように、データ・アクセスのロジックを切り出し、まとめたクラスのこと。


図6 リポジトリ・クラスとは?

 アクション側では、リポジトリ・クラスを通じてのみデータベースにアクセスするので、データベースの存在を意識する必要がなくなる(=コレクションとしてのみ見える)。また、インターフェイスを介してリポジトリ・クラスにアクセスするので、テスト時にもダミーのデータを返すだけのスタブを、簡単に割り込ませられる。

 ASP.NET MVCによるModelとは、これまで扱ってきたようなデータ・モデルと、このリポジトリ・クラスによって構成されると考えればよいだろう。

■リポジトリ・クラスの準備

 それでは、以下では第2回で扱った書籍管理アプリケーションを、リポジトリ・クラスを利用して書き直してみよう。ただし、紙面の都合上、リポジトリ・クラスに移動するのは、Index/Createアクションのロジックに限定するものとする。

[1]インターフェイスを準備する

 前述したように、リポジトリ・クラスにはインターフェイスを介してアクセスさせるのが一般的だ。よって、まずはIBooksRepositoryのようなインターフェイスを準備しておく。

using System.Collections.Generic;

namespace MvcTemplate.Models
{
  public interface IBooksRepository
  {
    List<Book> GetAllBooks();
    Book CreateBook(Book bok);
  }
}
Public Interface IBooksRepository
  Function GetAllBooks() As List(Of Book)
  Function CreateBook(ByVal bok As Book) As Book
End Interface
リスト8 リポジトリ・クラスの機能を定義したインターフェイス(上:IBooksRepository.cs、下:IBooksRepository.vb)

[2]リポジトリ・クラス(実装クラス)を準備する

 続いて、IBooksRepositoryインターフェイスを実装したリポジトリ・クラス本体を定義する。メソッドの内容については、アクション・メソッドにもともとあったデータ・アクセスのコードを移動しただけであるので、特筆すべき点はない。

using System.Collections.Generic;
using System.Linq;

namespace MvcTemplate.Models
{
  public class BooksRepository : IBooksRepository
  {
    // コンテキスト・クラスを生成
    private MyMvcContext _db = new MyMvcContext();

    // すべての書籍情報を取得
    public List<Book> GetAllBooks()
    {
      return _db.Books.ToList();
    }

    // 指定された書籍情報に基づいて、Booksテーブルに新規登録
    public Book CreateBook(Book bok)
    {
      _db.Books.Add(bok);
      _db.SaveChanges();
      return bok;
    }
  }
}
Public Class BooksRepository : Implements IBooksRepository

  ' コンテキスト・クラスを生成
  Private _db As New MyMvcContext()

  ' すべての書籍情報を取得
  Public Function GetAllBooks() As List(Of Book) Implements IBooksRepository.GetAllBooks
    Return _db.Books.ToList()
  End Function

  ' 指定された書籍情報に基づいて、Booksテーブルに新規登録
  Public Function CreateBook(bok As Book) As Book Implements IBooksRepository.CreateBook
    _db.Books.Add(bok)
    _db.SaveChanges()
    Return bok
  End Function
End Class
リスト9 データ・アクセスのコードを実装したリポジトリ・クラス(上:BooksRepository.cs、下:BooksRepository.vb)

[3]コントローラ・クラスを修正する

 コントローラ側もリポジトリ・クラスを呼び出すように修正しておこう(修正個所は太字)。

private IBooksRepository _rep;

// デフォルト・コンストラクタ(本番用)
public BooksController() : this(new BooksRepository()) { }

// テスト環境で利用するコンストラクタ
public BooksController(IBooksRepository rep)
{
  _rep = rep;
}


public ViewResult Index()
{
  // リポジトリ・クラス経由で書籍情報を取得
  return View(_rep.GetAllBooks());
}

……中略……

[HttpPost]
public ActionResult Create(Book book)
{
  if (ModelState.IsValid)
  {
    // リポジトリ・クラス経由で書籍情報を登録
    _rep.CreateBook(book);
    return RedirectToAction("Index");
  }
  return View(book);
}
Private _rep As IBooksRepository

' デフォルト・コンストラクタ(本番用)
Public Sub New()
  Me.New(New BooksRepository())
End Sub

' テスト環境で利用するコンストラクタ
Public Sub New(ByVal rep As IBooksRepository)
  _rep = rep
End Sub


Function Index() As ViewResult
  ' リポジトリ・クラス経由で書籍情報を取得
  Return View(_rep.GetAllBooks())
End Function

<HttpPost()>
Function Create(book As Book) As ActionResult
  If ModelState.IsValid Then
  ' リポジトリ・クラス経由で書籍情報を登録
    _rep.CreateBook(book)
    Return RedirectToAction("Index")
  End If
  Return View(book)
End Function
リスト10 リポジトリ・クラスを利用するように修正したコントローラ(上:BooksController.cs、下:BooksController.vb)

 デフォルト・コンストラクタ( )は、本番環境で動作することを想定したもので、それぞれのアクション・メソッドからリポジトリ・クラスにアクセスできるよう、これをインスタンス化し、プライベート・フィールドに保存している。

 一方、IBooksRepositoryインターフェイスを受け取るコンストラクタは、テストで利用することを想定したものだ( )。先ほどの図でも見たように、テストではダミーのデータを返すスタブでリポジトリ・クラスを差し替える必要がある。よって、これを受け取れる口を、ここで用意しておく必要があるわけだ。


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

本日 月間