HttpContextを単体テストする正しい方法は何ですか?
絶対無理。HttpContext
このコンテキストがまだ初期化されていないときに、コントローラーのコンストラクター内で使用しています。このコードはテストできないだけでなく、アプリケーションを実行すると NRE でクラッシュします。コントローラーのコンストラクターで HttpContext 関連のものを使用しないでください。
1 つの可能性は、コードをリファクタリングし、Initializeメソッド内でこれを実行することです。
public class BaseController : Controller
{
private IPolicy Policy;
protected override void Initialize(RequestContext requestContext)
{
base.Initialize(requestContext);
this.Policy = new Policy(HttpContext);
}
}
そうは言っても、それは私が推奨するアプローチではありません。多くの人がアンチパターンと見なしているサービス ロケーションの代わりに、依存性注入を使用することをお勧めします。
そう:
public abstract class BaseController : Controller
{
protected IPolicy Policy { get; private set; }
protected BaseController(IPolicy policy)
{
Policy = policy;
}
}
あとは、好きな依存性注入フレームワークを構成して、正しいインスタンスをコンストラクターに注入するだけです。たとえば、Ninject.Mvc3 では、これは 1 行のコードで実現されます。
kernel.Bind<IPolicy>().To<Policy>();
これで、HttpContext を気にすることなく、単体テストでこの IPolicy を自由にモックできるようになりました。
たとえば、単体テストする次のコントローラーがあるとします。
public class FooController : BaseController
{
public FooController(IPolicy policy): base(policy)
{ }
[Authorize]
public ActionResult Index()
{
Policy.DoSomething();
return View();
}
}
あとは、お気に入りのモック フレームワーク (私の場合は Rhino Mocks) を選択して、モックを作成するだけです。
[TestMethod]
public void Index_Action_Should_DoSomething_With_The_Policy()
{
// arrange
var policyStub = MockRepository.GenerateStub<IPolicy>();
var sut = new FooController(policyStub);
// act
var actual = sut.Index();
// assert
Assert.IsInstanceOfType(actual, typeof(ViewResult));
policyStub.AssertWasCalled(x => x.DoSomething());
}