この質問は、しばらくの間私を悩ませてきた質問なので、いくつかの興味深い答えが出ることを願っています。
ASP.NET MVCでコントローラーをユニットテストする際に実際の値はありますか?
つまり、ほとんどの場合(そして私は天才ではありません)、私のコントローラーメソッドは、次のような最も複雑なものでさえもです。
public ActionResult Create(MyModel model)
{
// start error list
var errors = new List<string>();
// check model state based on data annotations
if(ModelState.IsValid)
{
// call a service method
if(this._myService.CreateNew(model, Request.UserHostAddress, ref errors))
{
// all is well, data is saved,
// so tell the user they are brilliant
return View("_Success");
}
}
// add errors to model state
errors.ForEach(e => ModelState.AddModelError("", e));
// return view
return View(model);
}
面倒な作業のほとんどは、MVCパイプラインまたはサービスライブラリのいずれかによって行われます。
だから多分尋ねるべき質問は次のようになるでしょう:
Request.UserHostAddress
とModelState
が壊れないでしょうか?これらをモックしようとする必要がありますか?私のポイントは本当にだと思います、以下を行うことは全く無意味で間違っているようです
[TestMethod]
public void Test_Home_Index()
{
var controller = new HomeController();
var expected = "Index";
var actual = ((ViewResult)controller.Index()).ViewName;
Assert.AreEqual(expected, actual);
}
明らかに、私はこの誇張された無意味な例に鈍感になっていますが、誰かがここに追加する知恵を持っていますか?
楽しみにしています...ありがとう。
非常に単純なものでも、単体テストは複数の目的に役立ちます
その特定のアクションについて、私は次のことをテストします
NullReferenceExceptionのリクエストとモデルのチェックを指摘しましたが、ModelState.IsValidがモデルのNullReferenceの処理を担当すると思います。
リクエストをモックアウトすると、Nullリクエストを防ぐことができます。Nullリクエストは、本番環境では一般的に不可能ですが、単体テストでは発生する可能性があります。統合テストでは、さまざまなUserHostAddress値を提供できます(コントロールに関する限り、リクエストは依然としてユーザー入力であり、それに応じてテストする必要があります)。
私のコントローラーも非常に小さいです。コントローラーの「ロジック」のほとんどは、フィルター属性(組み込みおよび手書き)を使用して処理されます。したがって、私のコントローラーには通常、ほんの少しのジョブしかありません:
ActionResult
を生成するほとんどのモデルバインディングはASP.NET MVCによって自動的に行われます。 DataAnnotationsも、ほとんどの検証を処理します。
テストするものがほとんどなくても、私は通常それらを書きます。基本的に、私のリポジトリが呼び出され、正しいActionResult
タイプが返されることをテストします。 ViewResult
には、正しいビューパスが返され、ビューモデルが期待どおりに見えることを確認するための便利なメソッドがあります。正しいコントローラ/アクションがRedirectToActionResult
に設定されていることを確認する別の方法があります。 JsonResult
などの他のテストがあります。
Controller
クラスをサブクラス化すると、残念なことに、内部でHttpContext
を使用する便利なメソッドが多数提供されます。これにより、コントローラの単体テストが困難になります。このため、通常はHttpContext
依存の呼び出しをインターフェイスの背後に配置し、そのインターフェイスをコントローラーのコンストラクターに渡します(私はNinject Web拡張機能を使用してコントローラーを作成しています)。このインターフェイスは通常、セッション、構成設定、IPrincipleおよびURLヘルパーにアクセスするためのヘルパープロパティを貼り付ける場所です。
これには相当の注意が必要ですが、それだけの価値があると思います。
明らかに、いくつかのコントローラはそれよりもはるかに複雑ですが、純粋にあなたの例に基づいています:
MyServiceが例外をスローするとどうなりますか?
補足として。
また、参照によってリストを渡すことの知恵に疑問を投げかけます(とにかく、c#は参照によって渡されるので不要ですが、そうでなかったとしても)-サービスがエラーメッセージを送り出すために使用できるerrorActionアクション(アクション)を渡しますその後、必要に応じて処理できます(リストに追加したり、モデルエラーを追加したり、ログに記録したりできます)。
あなたの例では:
refエラーの代わりに、(string s)=> ModelState.AddModelError( ""、s)などを実行します。