moqの基本
実際にmoqを使うための基本を解説します。
moqではMockクラスが基本となります。そしてMockクラスを扱う上で最低限抑えておくべきメソッドはSetupメソッドです。
Setupメソッドのパラメータとしてラムダ式を記述します。モックオブジェクトはラムダ式の右辺で記述したメソッドの振る舞いを持ちます。Setupメソッド内で設定されたメソッドの戻り値はReturnメソッドのパラメータに記述します。
説明だけだとイメージしづらいと思いますので実際の構文を見てみましょう。構文例は以下のとおりです。
// テストしたいクラスのモックオブジェクトを作成 Mock<テストしたいクラス> mock = new Mock<テストしたいクラス>(); mock.Setup(m => m.テストしたいメソッド名(パラメータ)).Returns(理想の戻り値);
モックオブジェクト生成構文は上記のとおりです。
MVCのControllerContextのモックオブジェクト生成時の記述例もご紹介します。
// Controllerのモックオブジェクト生成例 Mock<ControllerContext> mock = new Mock<ControllerContext>(); mock.SetupGet(p => p.HttpContext.User.Identity.Name).Returns("Naokio");
ユーザー認証のフィルターが正確に動作しているかどうかテストしたい場合、上記モックオブジェクト生成コードを使うことになります(上記コードでは、Naokioというユーザー名を取得できるモックオブジェクトを生成しています)。
本来はアプリケーションサーバーを立てて実際に動作させて、ユーザーを用意しなければユーザーネームは取得できませんが、moqを使うことで、HttpContextオブジェクトやユーザーをあたかも実在しているかのように振る舞わせるモックオブジェクトを生成できます。
なお、設定したモックオブジェクトを取得するにはObjectプロパティを使用します。取得したモックオブジェクトはモックオブジェクト生成時に指定したクラスと同様の使い方ができます。
moqを利用する上でお作法が1つあります。それは、モックオブジェクト元のクラスの対象メソッドにvirtual修飾子を付けるというお作法です。テストを先に記述する場合、形だけのクラスやメソッドを作成しますが、moqではメソッドのオーバーライドを実施するため、virtual修飾子が必要になります。
なお、ControllerContextのプロパティやメソッドはvirtualで記述されているため、このお作法を意識することなくモックオブジェクトの作成が可能です。
続いて、ラムダ式内で記述するメソッドのパラメータに活用するItクラスについて紹介します。Itクラスは単体テストをより簡易に分かりやすく記載するための条件判定を実施できるメソッドを保有し、条件にマッチした場合Returnsメソッドの設定値を取得できます。条件判定をメソッド単位で実現できるのでIf文などの記載も不要になり可読性も向上します。
Itクラスで活用するメソッドは以下のとおりです。
メソッド名 | 概要 |
IsAny | パラメータで指定された型が渡された場合すべて許容する |
IsInRange | パラメータで指定した範囲内の値が渡された場合許容する |
IsRegex | パラメータで指定した正規表現にマッチする場合許容する |
構文例は以下のとおりです。
// テストしたいクラスのモックオブジェクトを作成 Mock<テストしたいクラス> mock = new Mock<テストしたいクラス>(); mock.Setup(m => m.テストしたいメソッド名(It.IsAny<型名>(パラメータ))).Returns(理想の戻り値); mock.Setup(m => m.テストしたいメソッド名(It.IsInRange<型名>(レンジ開始値,レンジ終了値,レンジの種類))).Returns(理想の戻り値); mock.Setup(m => m.テストしたいメソッド名(It.IsRegex(正規表現))).Returns(理想の戻り値);
各メソッドの利用例は以下のとおりです。
// すべてのstring型を許容し文字列を返す mock.Setup(m => m.テストしたいメソッド名(It.IsAny<string>())).Returns("文字列取得しました。"); // 5~15以内の数値の場合許容し文字列を返す mock.Setup(m => m.テストしたいメソッド名(It.IsInRange<int>(5,15,Range.Inclusive))).Returns("5~15の範囲の数値を取得しました。"); // 正教表現にマッチした場合許容し文字列を返す mock.Setup(m => m.テストしたいメソッド名(It.IsRegex(^(WINGSプロジェクト|wingsプロジェクト)$))).Returns("正規表現とマッチしました。");
MVCでは基本的に上記クラスとメソッドの活用を把握していれば単体テストを記述できるようになります。
まとめ
今回はMVC 3のサンプルプロジェクトに対する単体テストの記述方法を、単体テストを利用する上でのTipsを織り交ぜながら紹介しました。今回のまとめは以下のとおりです。
- 単体テストはバグを早期発見しコードの品質を高めることができる
- .NETにおける単体テストフレームワークとしてMSTestがProfessional Edition以上で利用できる
- テストで扱うモックはmoqを使用することで単体テストが容易に実現できる
以上を踏まえて次回は第4回で作成したDIプロジェクトの単体テストを記述しつつ、単体テストのポイントをご紹介していきます。お楽しみに。