如何在MVC4中抽象出响应对象进行测试?

时间:2013-04-01 21:58:06

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

我的MVC4 Web应用程序中有一些控制器操作,它们使用Response对象来访问查询字符串变量等。抽象的最佳做法是什么,因此它不会干扰单元测试操作?

1 个答案:

答案 0 :(得分:5)

MVC4团队已将HttpContext个相关属性抽象化,以便可以对其进行模拟,因此Response现在属于HttpResponseBase类型,因此已经被抽象掉了。你可以模拟对它的调用。

以下是我过去用于在单元测试场景中初始化控制器的标准方法。这是关于最小起订量的。我创建了一个假的http上下文,根据需要模拟各种相关的属性。您可以修改它以适合您的确切方案。

在实例化控制器之后,我将它传递给这个方法(也许在基类中 - 我使用NBehave进行单元测试,但是我不会在这里特别注意与之相关的任何事情):

protected void InitialiseController(T controller, NameValueCollection collection, params string[] routePaths)
{
    Controller = controller;
    var routes = new RouteCollection();
    RouteConfig.RegisterRoutes(routes);
    var httpContext = ContextHelper.FakeHttpContext(RelativePath, AbsolutePath, routePaths);
    var context = new ControllerContext(new RequestContext(httpContext, new RouteData()), Controller);
    var urlHelper = new UrlHelper(new RequestContext(httpContext, new RouteData()), routes);
    Controller.ControllerContext = context;
    Controller.ValueProvider = new NameValueCollectionValueProvider(collection, CultureInfo.CurrentCulture);
    Controller.Url = urlHelper;
}

ContextHelper是模拟所有设置的地方:

public static class ContextHelper
{
    public static HttpContextBase FakeHttpContext(string relativePath, string absolutePath, params string[] routePaths)
    {
        var httpContext = new Mock<HttpContextBase>();
        var request = new Mock<HttpRequestBase>();
        var response = new Mock<HttpResponseBase>();
        var session = new Mock<HttpSessionStateBase>();
        var server = new Mock<HttpServerUtilityBase>();
        var cookies = new HttpCookieCollection();

        httpContext.Setup(x => x.Server).Returns(server.Object);
        httpContext.Setup(x => x.Session).Returns(session.Object);
        httpContext.Setup(x => x.Request).Returns(request.Object);
        httpContext.Setup(x => x.Response).Returns(response.Object);
        response.Setup(x => x.Cookies).Returns(cookies);
        httpContext.SetupGet(x => x.Request.Url).Returns(new Uri("http://localhost:300"));
        httpContext.SetupGet(x => x.Request.UserHostAddress).Returns("127.0.0.1");
        if (!String.IsNullOrEmpty(relativePath))
        {
            server.Setup(x => x.MapPath(relativePath)).Returns(absolutePath);
        }

        // used for matching routes within calls to Url.Action
        foreach (var path in routePaths)
        {
            var localPath = path;
            response.Setup(x => x.ApplyAppPathModifier(localPath)).Returns(localPath);
        }

        var writer = new StringWriter();
        var wr = new SimpleWorkerRequest("", "", "", "", writer);
        HttpContext.Current = new HttpContext(wr);
        return httpContext.Object;
    }
}

我最近撰写了一篇博文,介绍了这种方法,但使用Nsubstitute作为模拟框架而不是MOQ

Unit testing Controllers using NUnit and NSubstitute