单元测试我的控制器方法导致一个空的ViewName?

时间:2009-04-05 06:28:07

标签: asp.net-mvc unit-testing controller

我正在对我的标准进行一些简单的MS单元测试,没有什么特殊的控制器。

当我从返回的ViewName对象中检查ViewResult属性时,它是""(空)。

我的印象是ViewName的名称隐含View(在ASP.NET MVC控制器测试中为suggested by this MS article)。

BTW,当我测试ViewData时,它就在那里并且正确。

这是我的代码......

public ActionResult Index(int? page, string tag)
{
    if (page == null || page <= 0)
    {
        page = 1;
    }

    var viewData = new IndexViewData
                       {
                       ... my property setters, etc ...
                       };
    return View(viewData);
}

[TestMethod]
public void Index_Action_Should_Return_Index_View_For_Default_HomePage()
{
    // Arrange.
    var controller = PostController; // Wrapper, cause I use D.I.

    // Act.
    ViewResult viewResult = controller.Index(null, null) as ViewResult;

    // Assert.
    Assert.IsNotNull(viewResult);
    Assert.AreEqual("Index", viewResult.ViewName); // This is false/fails.

    var indexViewData = viewResult.ViewData.Model as IndexViewData;
    Assert.IsNotNull(indexViewData); // This is true.
}

4 个答案:

答案 0 :(得分:28)

只有在ViewResult中设置ViewName时才会出现。如果您的视图名称与您的控制器名称匹配,那么我将检查以确保ViewName为null或为空,因为您将不希望在视图上设置名称(IMO)正确的行为。我只检查ViewName是否已设置,当我打算返回的视图与操作不匹配时 - 例如,返回“错误”视图时,例如。

编辑:以下是ViewResultBase.cs中ExecuteResult的来源(来自RC1,我的Macintosh上没有RTW源)。正如您所看到的,它会检查是否已直接设置ViewName,如果没有,则将其从控制器上下文的路由数据中的操作中提取出来。这只发生在ExecuteResult中,在控制器的操作完成后调用它。

    public override void ExecuteResult(ControllerContext context) {
        if (context == null) {
            throw new ArgumentNullException("context");
        }
        if (String.IsNullOrEmpty(ViewName)) {
            ViewName = context.RouteData.GetRequiredString("action");
        }

        ViewEngineResult result = null;

        if (View == null) {
            result = FindView(context);
            View = result.View;
        }

        ViewContext viewContext = new ViewContext(context, View, ViewData, TempData);
        View.Render(viewContext, context.HttpContext.Response.Output);

        if (result != null) {
            result.ViewEngine.ReleaseView(context, View);
        }
    }

答案 1 :(得分:2)

我个人发现MVC2提供的测试设备有点笨拙。我猜测已经存在一些更好的东西了,但我最终创建了一个简单的类来测试动作。我在一个名为MockRoundTrip的优秀开源Java MVC framework Stripes提供的类上建模了界面(实现是另一个故事)。

以下是测试操作时用于获取操作目标页面的方法,称为getTripDestination()。无论视图名是否明确设置,它都会返回正确的结果

    //Get the destination page of the request, using Runtime execution pattern of MVC, namely
    //if no ViewName is explicitly set in controller, ViewResult will have an empty ViewName
    //Instead, current action name will be used in its place
    public string getTripDestination()
    {
       RouteData routeData = getRouteData();
       ViewResult viewResult = (result is ViewResult) ? (ViewResult)result : null;
       string tripDestination = (viewResult != null) ? viewResult.ViewName : "";

       return (tripDestination != "") ? tripDestination : (String)routeData.Values["action"];
    }

    private RouteData getRouteData()
    {
       HttpContextBase context = controller.ControllerContext.RequestContext.HttpContext;
       return RouteTable.Routes.GetRouteData(context);
    }

答案 2 :(得分:0)

视图名由框架自动设置。但是当我们进行单元测试时,我们将框架短路,并且没有任何东西可以设置名称。

因此我们的操作需要在单元测试时明确设置视图名。如果我们确实真的想要依靠惯例,我们也可以检查null或为空。

答案 3 :(得分:0)

documentation for Controller.View()州:

  

View类的此方法重载返回一个ViewResult对象   具有空ViewName属性。如果你正在编写单元测试   控制器动作,考虑到空的ViewName属性   不采用字符串视图名称的单元测试。

     

在运行时,如果ViewName属性为空,则为当前操作   name用于代替ViewName属性。

因此,当期望与当前操作同名的视图时,我们可以测试它是否为空字符串。

或者,Controller.View(String)方法将设置ViewName。