しばやん雑記

Azure とメイドさんが大好きなフリーランスのプログラマーのブログ

ASP.NET MVC 3 開発入門 (6) - コントローラの実装

ASP.NET MVC 3 開発入門 - インデックス

コントローラには先程作成したリポジトリを持たせないとアクションの実装が出来ませんので、VideoController クラスに IVideoRepository 型のフィールドを追加しましょう。そして追加したフィールドにインスタンスをセットするのですが、外部から使用するリポジトリのインスタンスを指定できないと、せっかくリポジトリを作ったのが無駄になってしまいます。例えば以下のように実装してしまうと使用するリポジトリが固定になってしまい、コントローラとリポジトリが密結合になってしまいます。

public class VideoController : Controller
{
    public VideoController()
    {
        // VideoRepository 固定になってしまう!!
        _videoRepository = new VideoRepository();
    }

    private readonly IVideoRepository _videoRepository;
}

インターフェースを使う理由はお分かりだと思いますが、テスト時には外部からモッククラスのインスタンスを渡すことになるので、インターフェースで定義しておかないとリポジトリを作った意味が無くなりますね。

そこでコンストラクタのオーバーロードを利用して、リポジトリを外部から指定可能にしてしまいます。方法としては引数なしのコンストラクタと IVideoRepository を受け取るコンストラクタの 2 つを追加するだけです。以下のように実装してみましょう。

public class VideoController : Controller
{
    // オーバーロードコンストラクタを呼び出す
    public VideoController()
        : this(new VideoRepository())
    {
    }

    // 外部から IVideoRepository 型のインスタンスを貰う
    public VideoController(IVideoRepository videoRepository)
    {
        _videoRepository = videoRepository;
    }

    private readonly IVideoRepository _videoRepository;
}

引数なしのコンストラクタでは必ず VideoRepository を作成してオーバーロードされたコンストラクタを呼び出します。ASP.NET MVC ランタイムは引数なしのコンストラクタを呼び出してコントローラクラスをインスタンス化しますので、引数なしのコンストラクタは必ず準備しておかないとエラーになってしまいます。

そして単体テスト時には IVideoRepository を受け取るオーバーロードされたコンストラクタを、モッククラスのインスタンスを指定して呼び出せば実行時に自由に挙動を変更することが出来ますね。具体的なコードを書いてみると以下のようになります。

// モックリポジトリ
var repository = new MockVideoRepository();

// モックをコントローラで使うようにする!
var controller = new VideoController(repository);

// アクションを呼び出す
var actual = controller.Details(1);

...

これで単体テストが容易に行えるコントローラの実装が完了しました。次回からはいよいよアクションの実装を行っていきたいと思います、お疲れ様でした。