0

我需要在基本控制器中设置一个适用于所有控制器实例的策略,如下所示:

  public class BaseController : Controller
    {

        private IPolicy Policy;

        public BaseController()
        {
            this.Policy= new Policy(HttpContext);
        }
    }

在 Policy 类中,我需要执行以下操作:

   this.httpContextBase.User.

问题:(更新

就使用 HttpContext 和单元测试而言,设计 BaseController 的更好方法是什么。

4

1 回答 1

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;
    }
}

现在,剩下的就是配置您最喜欢的依赖注入框架以将正确的实例注入构造函数。例如,使用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());
}
于 2012-05-26T07:19:26.533 回答