3.テストクラス(Controller)への適用
ASP.NET MVCで容易になった単体テストですが、リポジトリパターンを扱うことでより安全に、精度の高いテストを実行できます。今回は似たようなテストになってしまうので2種類のテストを確認してみたいと思います。
実際のサンプルは以下の図のようになります(図3~4)。
Indexメソッドの検証
それでは実際にテストを行います。まずは一番シンプルなIndexから。
using RepositorySample.Controllers; using Microsoft.VisualStudio.TestTools.UnitTesting; using System.Web.Mvc; using Moq; using RepositorySample.Tests.Model; using System.Linq; namespace RepositorySample.Tests { <中略> // テストデータの作成 PubsController CreateTestPubsController() { var TestData = FakePubsData.CreateTestData(); var repository = new Model.PubsRepositoryTest(TestData); return new PubsController(repository); } <中略> [TestMethod()] public void IndexTest() { // PubsControllerの準備 PubsController pubsCon = CreateTestPubsController(); // 実行 var result = pubsCon.Index(); // 検証 Assert.IsInstanceOfType(result, typeof(ViewResult)); }
最初にCreateTestPubsControllerメソッドを作成し、すべてのテストメソッドで共通的に利用できるPubsControllerを生成します。
CreateTestPubsControllerメソッド内では、CreateTestDataメソッドでList型を生成し、その値をパラメタとしてPubsRepositoryTestに渡します。最後に、リポジトリモッククラスのパラメタを持たせたPubsControllerを返します。
IndexTestメソッド側では、生成されたPubsControllerに対してIndexメソッドを実行した結果をresult変数に格納しています。最後にresult変数がViewResultのインスタンスかどうかをIsInstanceOfTypeメソッドを使って検証しています。
Editメソッドの検証
第2回ではFormCollection型がViewPage側で入力された項目すべてのデータを持つCollectionであることを解説しました。利用方法はString型のキーとデータを同時に指定することで、データを格納します。このFormCollectionを有効活用するシナリオとして単体テスト時が挙げられます。つまり、通常実行時は活躍の場所がなくとも、単体テスト時に入力項目を用意して埋め込めば入力ポスト時のテストが行えるのです。
using RepositorySample.Controllers; using Microsoft.VisualStudio.TestTools.UnitTesting; using System.Web.Mvc; using Moq; using RepositorySample.Tests.Model; using System.Linq; namespace RepositorySample.Tests { <中略> // テストデータの作成 PubsController CreateTestPubsController() { var TestData = FakePubsData.CreateTestData(); var repository = new Model.PubsRepositoryTest(TestData); return new PubsController(repository); } <中略> [TestMethod()] public void EditTest() { // PubsControllerとFormCollectionの準備 PubsController pubsCon = CreateTestPubsController(); var form = FakePubsData.CreateTitlesFormCollection(); pubsCon.ValueProvider = form.ToValueProvider(); // 実行 ActionResult result = (ActionResult)pubsCon.Edit("1", form); // 検証 Assert.AreEqual(5, pubsCon.ModelState.Count); Assert.AreEqual("Tamaki's Photo Diary", pubsCon.ModelState["title"].Value.AttemptedValue); }
Edit部分では"既に登録されているデータ(ここではモックデータ)と、変更があった部分のデータ(FormCollectionによるデータ)"の差分が適切に編集更新されているかどうかをテストします。
Indexの時同様にCreateTestPubsControllerメソッドでPubsControllerを生成します(モックデータの生成)。続いて、FakePubsDataクラスで用意した、FormCollectionのモックデータを生成(更新部分のデータ作成)します。
CreateTitlesFormCollectionメソッドを使い、取得したFormCollectionのデータをPubsControllerクラスのValueProviderプロパティに格納します。
ValueProviderプロパティとは、UpdateModelメソッドの更新内容パラメタとして、利用できるプロパティです(UpdateModelメソッドは第一パラメタに更新対象を、第2パラメタに更新内容を指定できます)。FormCollectionはView側の入力フォームのデータをすべて持っているので、その中から更新したい内容を渡すプロバイダとしてValueProviderプロパティがあると捉えてもらっても構いません。
続いて、Editメソッドを実行した結果をresult変数に格納しています。最後にFormCollectionのデータの数が一致するか、ModelStateの数でテストします。
ModelStateコレクションは、アクションメソッドに渡されているプロパティまたはModelの状態を格納しているコレクションです。また、エラーなどの内容も格納されるのは第2回の検証機能で紹介したとおりです。
続けて、FormCollectionデータ作成時に格納した値と一致するかもModelState["キー名"].Value.AttemptedValueプロパティを使い確認します。AttemptedValueプロパティとは、View側で実際に表示されるフォーマット前Stringの値が入っています。
リポジトリパターンを扱うことで、大抵ActionResultが返されるASP.NET MVCにおけるテストの容易さ、確実性の向上が望めることがお分かりいただけたかと思います。
まとめ
今回はASP.NET MVCで実開発を行う際に利用されるメジャーな開発パターンであるリポジトリパターンについて概要とメリットを紹介しました。今回触れた内容は単純にデータアクセスロジックをControllerから取り出すところまででしたが、さらに機能ごとに分離させることで、Controllerをよりスッキリした記述に変えることなども可能です。
また、複雑なシステムであっても、今回触れたリポジトリパターンを活かすことでテスト、開発共にパワフルに行えます。ぜひ、本稿の内容を足がかりにリポジトリパターンをマスターしていただければと思います。