如何使用moq模拟控制器上下文

时间:2009-07-30 14:22:37

标签: c# .net asp.net-mvc moq

我正在试用MOQ框架,现在我已经遇到了障碍。以下单元测试失败,因为ViewName属性的实际值是空字符串。

有人能指出我正确的方向,为什么这不通过测试?

[TestMethod]
public void Can_Navigate_To_About_Page()
{
    var request = new Mock<HttpRequestBase>();
    request.Setup(r => r.HttpMethod).Returns("GET");
    var mockHttpContext = new Mock<HttpContextBase>();
    mockHttpContext.Setup(c => c.Request).Returns(request.Object);

    var controllerContext = new ControllerContext(mockHttpContext.Object, 
                                new RouteData(), 
                                new Mock<ControllerBase>().Object);
    var controller = new HomeController();

    controller.ControllerContext = controllerContext;
    var result = controller.About() as ViewResult;

    Assert.AreEqual("About", result.ViewName);
}

以下内容还会产生一个空的ViewName。

        HomeController controller = new HomeController();
        ViewResult result = controller.About() as ViewResult;
        Assert.IsNotNull(result);
        Assert.AreEqual("About", result.ViewName);

从网上展示模拟和良好TTD的例子我只是对于我需要做出上述第一个单元测试示例工作的其他管道工作感到困惑。

干杯,

安德鲁

2 个答案:

答案 0 :(得分:7)

测试失败的原因是因为当您没有明确指定ViewName时,决定ViewName的是在框架的深度。更确切地说,在视图引擎中我相信。因此,为了测试它,你将不得不模拟更多的请求管道。

我所做的并且建议不要依赖默认值并明确指定视图:

return View("About");

然后值将在那里进行测试而不会嘲笑任何东西:

var controller = new HomeController();
var result = controller.About() as ViewResult;
Assert.AreEqual("About", result.ViewName);

答案 1 :(得分:3)

这是因为您正在假设MVC框架是如何工作的。如果您依赖约定来查找视图,那么框架实际上会将ViewName属性保留为String.Empty,直到调用ExecuteResult()

您可以在the MVC source内的ViewResultBase.ExecuteResult第68行看到此代码:

if (String.IsNullOrEmpty(ViewName)) {
   ViewName = context.RouteData.GetRequiredString("action");
}

此外,您应该注意您正在测试的内容。根据经验,您应该专注于测试您编写的代码,而不是框架的代码。测试以确保按惯例正确解析视图名称实际上是框架本身的单元测试,而不是构建在其上的应用程序。

如果您正在寻找一种在MVC中使用模拟的好方法,您可能需要考虑测试您的路线(这类似于您在此尝试做的事情)。您可以find a post by Phil Haack concerning just this subject让您入门。