読者です 読者をやめる 読者になる 読者になる

miso_soup3 Blog

主に ASP.NET 関連について書いています。

MvcScaffolding で MVCのControllerテストを効率よく

MvcScaffolding を使えば、
アクションメソッドとそのテスト、他いろいろなものを自動生成してくれます。

使ってみた感想と、カスタマイズ方法の一部を記載します。

感想

  • すごい!らくちん!
  • コードの変更は、t4をいじるだけなので簡単。
  • ファイルが生成される場所を変更するのが、ちょっと大変。(ViewModelとかテスクラストとか。)
  • 恐らく、MvcScaffoldingをデフォルトのまま利用することはできない。いじっているうちに、プロジェクト固有の生成ツールになっちゃうと思う。

MvcScaffolding とは

NuGet package です。
たとえば

PM> Scaffold Action Home PersonList -WithViewModel

と打つと、

  • Viewフォルダにて PersonList.csHtml の追加
  • HomeController クラスに、 PersonList アクションメソッド生成
  • PersonListViewModel クラスの追加(生成したメソッドにも記述が!)
  • PersonList のテストクラスを追加し、テストメソッドまで書いてくれる

以上のことをしてくれます。

PM> Scaffold Action Home PersonList -WithViewModel -Post

Post をつければ、Post用のコードも生成してくれます。
(アクションメソッドの引数に、ViewModelが渡されている!)

チュートリアルは MvcScaffolding で確認できます。
非常に丁寧に書かれているので、どんな感じで生成されるのか、一目でわかります。

ひっかかったところ:テストクラス生成場所の変更

Testクラスが生成されるプロジェクト名にはルールがあります。

OKなケース

チュートリアルはこのプロジェクト構成を対象にしています。Mvcの初期構成です。
テストプロジェクト名の末尾は、.Tests でも OK。

Controllerプロジェクトを別に作成しても、Testクラスを生成してくれます。
(プロジェクトの参照は必要)

カスタマイズしないと生成してくれないケース

テストプロジェクト名が、プロジェクト名 + ".Test(Tests)" でない場合、
カスタマイズしないとTestクラスを生成してくれません。

テストプロジェクト名を指定する方法

手っ取り早く、方法だけ記載します。

〜プロジェクトフォルダ\packages\MvcScaffolding.1.0.6\tools\ActionUnitTest
の、
MvcScaffolding.ActionUnitTest.ps1 の中身を以下のように変更します。

1.17行目あたり

$unitTestProject = Get-Project ($Project + ".Test") -ErrorAction SilentlyContinue

$unitTestProject = Get-Project ("MvcApplication4.Test.Controller") -ErrorAction SilentlyContinue

 テストプロジェクト名を記載

2.29行目あたり

$testClassNamespace = $unitTestProject.Properties.Item("DefaultNamespace").Value
$defaultNamespace = $unitTestProject.Properties.Item("DefaultNamespace").Value

$testClassNamespace = $unitTestProject.Name
$defaultNamespace = $unitTestProject.Name

以上です。
ちなみに、2.の変更について、チュートリアルサイトの最後の方でコメントされている方がいらっしゃいました。

おまけ

Mvcのテストが流行っている??ので、
よく使うControllerテストクラスのscaffoldを記載。

[TestFixture]
Public class HomeControllerTest
{
	private Component _component;

	[SetUp]
        public void Setup()
        {
            _component = new Component();
        }

        [TearDown]
        public void TearDown()
        {
            _component.VerifyAll();
        }
        
        private class Component
        {
            public Mock<IPersonRepository> PersonRepositoryMock = new Mock<IPersonRepository>();
            public Mock<IBookRepository> BookRepositoryMock = new Mock<IBookRepository>();

            public void VerifyAll()
            {
                PersonRepositoryMock.VerifyAll();
                BookRepositoryMock.VerifyAll();
            }
        }

        private HomeController CreateController(Component component)
        {
            return new HomeController(
                component.BookRepositoryMock.Object,
                component.PersonRepositoryMock);
        }

        #region ListTest

        /// <summary>
        /// 一覧テスト
        /// サービスを正しく利用しているかどうか
        /// </summary>
        [Test]
        public void List_Service_Test()
        {
        	//(^^)
        }

        /// <summary>
        /// 一覧テスト
        /// サービスが例外を投げてきたとき
        /// </summary>
        [Test]
        public void List_Service_Failure_Test()
        {
		//_(..)_
        }

        /// <summary>
        /// 一覧テスト
        /// ModelState.IsInvalidなとき
        /// </summary>
        [Test]
        public void List_ModelState_IsInvalid_Test()
        {
		//('_')
        }

        #endregion
}

なんとなくメソッドの名前は日本語にした方がよい気も・・・。

とうとう4月だー!