Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Render a View during a Unit Test - ControllerContext.DisplayMode

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.Mvc\Views\Report\Index.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?

like image 867
Philip Pittle Avatar asked Jan 22 '15 11:01

Philip Pittle


People also ask

What does a unit test attempt to achieve?

The purpose of a unit test in software engineering is to verify the behavior of a relatively small piece of software, independently from other parts. Unit tests are narrow in scope, and allow us to cover all cases, ensuring that every single part works correctly.


1 Answers

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
like image 95
B2K Avatar answered Sep 29 '22 04:09

B2K