Render a View during a Unit Test

I am working on an ASP.NET MVC 4 web application that generates large and complicated reports. I want to write Unit Tests that render a View in order to make sure the View doesn't blow up depending on the Model:

 [Test]
 public void ExampleTest(){                  
     var reportModel = new ReportModel();

     var reportHtml = RenderRazorView(
           @"....Report.MvcViewsReportIndex.cshtml", 
           reportModel);

     Assert.IsFalse(
         string.IsNullOrEmpty(reportHtml),
         "View Failed to Render!");          
 }

 public string RenderRazorView(string viewPath, object model){
    //WHAT GOES HERE?
 }

I have seen a lot of information about this around the web, but it's either arguing against testing vies, or can only be used in the context of a web request.

  • Arguing Against - Unit Testing the Views? - This concludes there should be no logic in the View so you should only need to test compilation. I think there is value in testing the View to make sure there aren't Null Reference Exceptions, the correct sections are shown, etc.
  • Context of a Web Request - Render a view as a string - This is to render a View to be sent in an email. But this approach requires being called via a web request (ie a valid HttpContextBase ).
  • I have been working to adapt Render a view as a string to work with a Mocked HttpContextBase , but have been running into problems when using a Mocked ControllerContext :

    Object reference not set to an instance of an object. at System.Web.WebPages.DisplayModeProvider.GetDisplayMode(HttpContextBase context) at System.Web.Mvc.ControllerContext.get_DisplayMode() at System.Web.Mvc.VirtualPathProviderViewEngine.GetPath(ControllerContext controllerContext, String[] locations, String[] areaLocations, String locationsPropertyName, String name, String controllerName, String cacheKeyPrefix, Boolean useCache, String[]& searchedLocations)

    This is the code I have so far:

        public string RenderRazorView(string viewPath, object model)
        {
            var controller = GetMockedDummyController();
    
            //Exception here
            var viewResult = 
                ViewEngines.Engines.FindView(controller.ControllerContext, "Index", "");
    
            using (var sw = new StringWriter())
            {
                var viewContext =
                    new ViewContext(
                        controller.ControllerContext,
                        viewResult.View,
                        new ViewDataDictionary(model),
                        new TempDataDictionary(),
                        sw);
    
                viewResult.View.Render(viewContext, sw);
    
                return sw.ToString();
            }
        }
    

    I'm building the Controller:

        private Controller GetMockedDummyController()
        {
            var HttpContextBaseMock = new Mock<HttpContextBase>();
            var HttpRequestMock = new Mock<HttpRequestBase>();
            var HttpResponseMock = new Mock<HttpResponseBase>();
            HttpContextBaseMock.SetupGet(x => x.Request).Returns(HttpRequestMock.Object);
            HttpContextBaseMock.SetupGet(x => x.Response).Returns(HttpResponseMock.Object);
    
            var controller = new DummyController();
    
            var routeData = new RouteData();
            routeData.Values.Add("controller", "Dummy");
    
            controller.ControllerContext = 
                new ControllerContext(
                    HttpContextBaseMock.Object,
                    routeData,
                    controller);
    
            controller.Url =
                new UrlHelper(
                    new RequestContext(
                        HttpContextBaseMock.Object,
                        routeData), 
                    new RouteCollection());
    
            return controller;
        }
    

    The DummyController is just public class DummyController : Controller {}

    Question

    Give the path to a View, how can I render it to HTML from a Test project? Or more specifically, how can I mock out the ControllerContext.DisplayMode ?


    Assuming you have complete separation of concerns, is it necessary to instantiate the controller at all? If not, then perhaps you can use RazorEngine to test your views.

    var contents = File.ReadAllText("pathToView"); 
    var result = Razor.Parse(contents,model);
    // assert here
    

    你将需要一个空的Controller来测试(例如TestController

    public class WebMvcHelpers
    {
        public static string GetViewPageHtml(object model, string viewName)
        {
            System.Web.Mvc.Controller controller = CreateController<TestController>();
    
            ViewEngineResult result = ViewEngines.Engines.FindPartialView(controller.ControllerContext, viewName);
    
            if (result.View == null)
                throw new Exception(string.Format("View Page {0} was not found", viewName));
    
            controller.ViewData.Model = model;
            StringBuilder sb = new StringBuilder();
            using (StringWriter sw = new StringWriter(sb))
            {
                using (System.Web.UI.HtmlTextWriter output = new System.Web.UI.HtmlTextWriter(sw))
                {
                    ViewContext viewContext = new ViewContext(controller.ControllerContext, result.View, controller.ViewData, controller.TempData, output);
                    result.View.Render(viewContext, output);
                }
            }
    
            return sb.ToString();
        }
    
        /// <summary>
        /// Creates an instance of an MVC controller from scratch 
        /// when no existing ControllerContext is present       
        /// </summary>
        /// <typeparam name="T">Type of the controller to create</typeparam>
        /// <returns></returns>
        public static T CreateController<T>(RouteData routeData = null)
                    where T : System.Web.Mvc.Controller, new()
        {
            T controller = new T();
    
            // Create an MVC Controller Context
            HttpContextBase wrapper = null;
            if (HttpContext.Current != null)
                wrapper = new HttpContextWrapper(System.Web.HttpContext.Current);
            //else
            //    wrapper = CreateHttpContextBase(writer);
    
    
            if (routeData == null)
                routeData = new RouteData();
    
            if (!routeData.Values.ContainsKey("controller") && !routeData.Values.ContainsKey("Controller"))
                routeData.Values.Add("controller", controller.GetType().Name
                                                            .ToLower()
                                                            .Replace("controller", ""));
    
            controller.ControllerContext = new System.Web.Mvc.ControllerContext(wrapper, routeData, controller);
            return controller;
        }
    }
    
    public class TestController : Controller
    {
        public ActionResult Index()
        {
            return View();
        }
    }
    
    链接地址: http://www.djcxy.com/p/83162.html

    上一篇: 在Woocommerce Orders Admin页面按订单商品SKU或ID搜索

    下一篇: 在单元测试期间渲染视图