我需要在基本控制器中设置适用于所有控制器实例的策略,如下所示:
public class BaseController : Controller
{
private IPolicy Policy;
public BaseController()
{
this.Policy= new Policy(HttpContext);
}
}
在Policy类中,我需要执行以下操作:
this.httpContextBase.User.
问题:(更新)
在使用HttpContext和Unit测试方面设计BaseController的更好方法是什么。
答案 0 :(得分:6)
单元测试HttpContext的正确方法是什么?
绝对没办法。当此上下文仍未初始化时,您正在控制器的构造函数内使用HttpContext
。不仅无法测试此代码,而且当您运行应用程序时,它也会因NRE而崩溃。你永远不应该在控制器的构造函数中使用任何与HttpContext相关的东西。
一种可能性是重构代码并在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;
}
}
现在,剩下的就是配置你喜欢的Dependency Injection框架,将正确的实例注入到构造函数中。例如,使用Ninject.Mvc3,只需一行代码即可实现:
kernel.Bind<IPolicy>().To<Policy>();
现在你可以在单元测试中自由地模仿这个IPolicy而不用关心任何HttpContext。
例如,假设您有以下要进行单元测试的控制器:
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());
}