MVC.NET单元测试RenderPartialViewToString

时间:2014-12-19 18:31:15

标签: c# asp.net-mvc unit-testing moq httpcontext

我是单元测试我的MVC.Net 4应用程序,我需要一些帮助来测试将视图呈现为字符串。

当我测试视图渲染到字符串崩溃时。

在我的控制器中,我调用以下行来创建要在Json对象中发回的html字符串。

String html = this.RenderPartialViewToString("~/Areas/Admin/Views/Statistics/Graphs/LineGraph.cshtml", orderData);

RenderPartialViewtoString方法如下:

public static string RenderPartialViewToString(this Controller controller, string viewName, object model)
{
        if (string.IsNullOrEmpty(viewName)) 
        {
            viewName = controller.ControllerContext.RouteData.GetRequiredString("action");
        }

        controller.ViewData.Model = model;

        using (var sw = new StringWriter())
        {
            // Find the partial view by its name and the current controller context.
            ViewEngineResult viewResult = ViewEngines.Engines.FindPartialView(controller.ControllerContext, viewName);

            // Create a view context.
            var viewContext = new ViewContext(controller.ControllerContext, viewResult.View, controller.ViewData, controller.TempData, sw);

            // Render the view using the StringWriter object.
            viewResult.View.Render(viewContext, sw);
            //viewResult.ViewEngine.ReleaseView(controller.ControllerContext, viewResult.View);

            return sw.GetStringBuilder().ToString();
        }
}

我正在使用Moq模拟HttpContext。

public static Mock<HttpContextBase> MockHttpContext()
    {
        var browser = new Mock<HttpBrowserCapabilitiesBase>();
        var context = new Mock<HttpContextBase>();
        var request = new Mock<HttpRequestBase>();
        var response = new Mock<HttpResponseBase>();

        var server = new Mock<HttpServerUtilityBase>();
        var cookies = new HttpCookieCollection();
        var items = new ListDictionary();
        var session = new MockHttpSession();

        browser.Setup(b => b.IsMobileDevice).Returns(false);

        request.Setup(r => r.Cookies).Returns(cookies);
        request.Setup(r => r.ValidateInput());
        //request.Setup(r => r.UserAgent).Returns("Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.64 Safari/537.11");
        response.Setup(r => r.Cookies).Returns(cookies);
        request.Setup(r => r.Browser).Returns(browser.Object);
        //request.Setup(r => r.AppRelativeCurrentExecutionFilePath).Returns("/");
        //request.Setup(r => r.ApplicationPath).Returns("/");
        request.Setup(x => x.Form).Returns(new NameValueCollection());

        response.Setup(s => s.ApplyAppPathModifier(It.IsAny<string>())).Returns<string>(s => s);
        response.SetupProperty(res => res.StatusCode, (int)System.Net.HttpStatusCode.OK);

        context.Setup(ctx => ctx.Request).Returns(request.Object);
        context.Setup(ctx => ctx.Response).Returns(response.Object);
        context.Setup(ctx => ctx.Session).Returns(session);
        context.Setup(ctx => ctx.Server).Returns(server.Object);
        context.Setup(ctx => ctx.Items).Returns(items);  

        return context;
    }

    public static Mock<HttpContextBase> MockHttpContext(string url)
    {
        var context = MockHttpContext();
        context.Object.Request.SetupRequestUrl(url);
        return context;
    }

    public class MockHttpSession : HttpSessionStateBase
    {
        Dictionary<string, object> m_SessionStorage = new Dictionary<string, object>();

        public override object this[string name]
        {
            get {
                try
                {
                    return m_SessionStorage[name];
                }
                catch (Exception)
                {
                    return null;
                }
            }
            set { m_SessionStorage[name] = value; }
        }

        public override void Remove(string name)
        {
            m_SessionStorage[name] = null;
        }
    }

    public static void SetMockControllerContext(this Controller controller,
        HttpContextBase httpContext = null,
        RouteData routeData = null,
        RouteCollection routes = null)
    {
        //If values not passed then initialise 
        routeData = routeData ?? new RouteData();
        routes = routes ?? RouteTable.Routes;
        httpContext = httpContext ?? MockHttpContext().Object;

        var requestContext = new RequestContext(httpContext, routeData);
        var context = new ControllerContext(requestContext, controller);

        //Modify controller
        controller.Url = new UrlHelper(requestContext, routes);
        controller.ControllerContext = context;
    }

使用前一个代码块中的方法将模拟上下文添加到控制器。

  

MvcMockHelpers.SetMockControllerContext(controller,httpContextMock.Object,routeData,routeCollection);

模拟ViewEngine以提供正确的视图:

IEnumerable<string> FileExtensions = new[]
{
 "cshtml"
 };

 IViewPageActivator viewPageActivator = null;
 var view = new RazorView(controller.ControllerContext, "Areas/Admin/Views/Statistics/Graphs/LineGraph.cshtml", layoutPath: null, runViewStartPages: false, viewStartFileExtensions: FileExtensions, viewPageActivator: viewPageActivator);

  //Mocking View Engine to make sure that the Partial View To String function works.
  var engine = new Mock<IViewEngine>();
  var viewEngineResult = new ViewEngineResult(view, engine.Object);
  engine.Setup(e => e.FindPartialView(It.IsAny<ControllerContext>(), It.IsAny<string>(),     It.IsAny<bool>())).Returns(viewEngineResult);
  ViewEngines.Engines.Clear();
  ViewEngines.Engines.Add(engine.Object);

然后我调用控制器动作方法来渲染视图

  

var result = controller.StatisticsUpdate(model);

我在System.Web.VirtualPath.GetCacheKey()

上获得了引用null异常

Stacktrace:

at System.Web.VirtualPath.GetCacheKey()
at System.Web.Compilation.BuildManager.GetCacheKeyFromVirtualPath(VirtualPath virtualPath, Boolean& keyFromVPP)
at System.Web.Compilation.BuildManager.GetVPathBuildResultFromCacheInternal(VirtualPath virtualPath, Boolean ensureIsUpToDate)
at System.Web.Compilation.BuildManager.GetVPathBuildResultInternal(VirtualPath virtualPath, Boolean noBuild, Boolean allowCrossApp, Boolean allowBuildInPrecompile, Boolean throwIfNotFound, Boolean ensureIsUpToDate)
at System.Web.Compilation.BuildManager.GetVPathBuildResultWithNoAssert(HttpContext context, VirtualPath virtualPath, Boolean noBuild, Boolean allowCrossApp, Boolean allowBuildInPrecompile, Boolean throwIfNotFound, Boolean ensureIsUpToDate)
at System.Web.Compilation.BuildManager.GetVirtualPathObjectFactory(VirtualPath virtualPath, HttpContext context, Boolean allowCrossApp, Boolean throwIfNotFound)
at System.Web.Compilation.BuildManager.GetVirtualPathObjectFactory(VirtualPath virtualPath, HttpContext context, Boolean allowCrossApp)
at System.Web.Compilation.BuildManager.GetCompiledType(VirtualPath virtualPath)
at System.Web.Compilation.BuildManager.GetCompiledType(String virtualPath)
at System.Web.Mvc.BuildManagerWrapper.System.Web.Mvc.IBuildManager.GetCompiledType(String virtualPath)
at System.Web.Mvc.BuildManagerCompiledView.Render(ViewContext viewContext, TextWriter writer)
at WebUi.Extensions.ControllerExtensions.RenderPartialViewToString(Controller controller, String viewName, Object model) in d:\Element Software\PlasticRepository\Nobastore\WebUi\Extensions\ControllerExtensions.cs:line 37
at WebUi.Areas.Admin.Controllers.OverviewController.StatisticsUpdate(StatisticsModel model) in d:\Element Software\PlasticRepository\Nobastore\WebUi\Areas\Admin\Controllers\OverviewController.cs:line 97
at UnitTests.ControllerTests.Admin.OverviewControllerTest.StatisticsUpdate_View_Test() in d:\Element Software\PlasticRepository\Nobastore\UnitTests\ControllerTests\Admin\OverviewControllerTest.cs:line 147`

我已经尝试了几天搜索源代码,但我无法找到问题,而且我无法在网络上找到任何体面的解决方案。

有人有答案吗?我在模仿httpcontext或controllercontext中遗漏了什么吗?

欢迎任何帮助。

0 个答案:

没有答案