单元测试中忽略ASP.NET MVC2自定义视图引擎

时间:2010-12-10 16:57:14

标签: unit-testing asp.net-mvc-2 viewengine

我正在尝试对将数据填充到ViewData中的控制器进行单元测试。我们所有的观点都需要类似的数据(客户信息来自网址)。因此,原始开发人员选择将此ViewData填充放入OnActionExecuting事件中,而不是将调用放入每个控制器方法中。

当然,当您从单元测试中调用控制器的操作时,OnActionExecuting不会触发。 (感谢MVC团队!)

所以我尝试创建一个自定义视图引擎,并在请求视图时将客户数据填充到controllerContext中。这在浏览器中工作正常,但是当我运行此测试时,我的viewEngine会被忽略。没有任何数量的ViewEngines.Add(新的funkyViewEngine)有任何影响。

  [TestMethod()]
            public void LoginTest()
            {
                ViewEngines.Engines.Clear();
                ViewEngines.Engines.Add(new FunkyViewEngine());

                UserController target = new UserController();
                target.SetStructureMap();  <--sets us to use the test repo

                target.ControllerContext.HttpContext = MVCHelpers.FakeHttpContext("https://customersubdomain.ourdomain.com");  <--moq magic
                var actual = target.Login();
                Assert.IsTrue(actual.GetType().IsAssignableFrom(typeof(System.Web.Mvc.ViewResult)));
                var  vr = actual as ViewResult;
                Assert.IsTrue(vr.ViewData.Community() != null);  <--"Community" should be set by viewengine
                Assert.IsTrue(vr.ViewData.Community().Subdomain == "customersubdomain.ourdomain");
                Assert.IsTrue(vr.ViewData.Community().CanRegister);
            }

这里有什么希望吗?我如何1)创建一个在浏览器和单元框架中调用控制器执行的方法或2)获取单元框架来调用我的视图引擎。

2 个答案:

答案 0 :(得分:2)

对不起你的沮丧。当您从单元测试直接调用您的操作方法时,您看到OnActionExecuting未被调用的原因是因为这不是MVC中的工作方式。

请求通过“管道”执行,就该区域而言,该管道由ControllerActionInvoker组成。本课程负责:

  1. 查找操作方法
  2. 调用操作过滤器“OnActionExecuting方法(注意:您的控制器类也是操作过滤器)
  3. 调用动作方法本身
  4. 调用操作过滤器“OnActionExecuted方法
  5. 处理结果(例如查找并呈现视图)
  6. 在您的单元测试中,您直接调用步骤3.并跳过所有其他步骤。在单元测试中,您有责任调用您的操作所需的任何设置代码。

    但是,这并不意味着您现在应该编写使用ControllerActionInvoker来执行整个管道的单元测试。我们(MVC团队)已经确认所有部分都在一起工作。

    相反,您应该测试您的特定应用程序代码。在这种情况下,您可以考虑进行以下单元测试:

    1. 一个测试,用于验证控制器上的某个Url调用OnActionExecuting是否将正确的Customer对象放入ViewData
    2. 一个测试,用于验证ViewData中存在一些Customer对象,您的操作方法会返回相应的结果
    3. 我的最后一点是你应该将功能保留在OnActionExecuting中。自定义视图引擎定义为错误的位置。

答案 1 :(得分:0)

不是您可能正在寻找的答案,但我使用自定义 MvcHandler 来实现相同的目标(在多租户应用中从URL获取客户)。 ViewEngine对我来说听起来不是这种逻辑的好地方......

我的自定义处理程序或多或少看起来像这样:

public class AccountMvcHandler : MvcHandler
{
    public Account Account { get; private set; }

    protected override IAsyncResult BeginProcessRequest(HttpContext httpContext, AsyncCallback callback, object state)
    {
        return base.BeginProcessRequest(httpContext, callback, state);
    }

    protected override IAsyncResult BeginProcessRequest(HttpContextBase httpContext, AsyncCallback callback, object state)
    {
        string accountName = this.RequestContext.RouteData.GetRequiredString("account");
        Account = ServiceFactory.GetService<ISecurityService>().GetAccount(accountName);

        return base.BeginProcessRequest(httpContext, callback, state);
    }
}