ViewContext is null when unit testing a view

Jun 13, 2013 at 10:04 PM
OK, my original set of questions that I got past were here:

https://razorgenerator.codeplex.com/discussions/440853

I took a bit of a break from this and am back trying to get the whole thing working.

Anyways, I have code that looks something like this (anonymized)
            var view = new HomePage();
            view.ViewData.Model = new HomePageModel(content, x, false);
            
            HtmlDocument doc = view.RenderAsHtml();
When I call RenderAsHtml, I get an exception that boils down to the ViewContext being null when System.Web.Mvc.WebViewPage.InitHelpers() is called. Ok. Do I need to mock up a context object and set in in my test as well? What other items will I need to mock?

Thanks
Matt
Coordinator
Jun 13, 2013 at 10:53 PM
There is a sample on https://razorgenerator.codeplex.com/SourceControl/latest#MvcViewsTests/TestViews.cs that works with RenderAsHtml. But it's possible that based on what the view is doing, it doesn't work in all cases. That test logic is still a bit experimental.
Jun 13, 2013 at 11:14 PM
This sample is very simple and doesn't show any more code than what I have (in fact, it uses the ViewBag rather than setting the model).

I (kind of) got around it by doing this:
            var view = new HomePage();
            view.ViewData.Model = new HomePageModel(content, x, false);
            view.ViewContext = new System.Web.Mvc.ViewContext();
            
            HtmlDocument doc = view.RenderAsHtml();
That got past the line that errored before, but I now get the following exception:
Value cannot be null.
Parameter name: viewData
   at System.Web.Mvc.ViewContext..ctor(ControllerContext controllerContext, IView view, ViewDataDictionary viewData, TempDataDictionary tempData, TextWriter writer)
   at RazorGenerator.Testing.WebViewPageExtensions.Initialize[TModel](WebViewPage`1 view, HttpContextBase httpContext)
   at RazorGenerator.Testing.WebViewPageExtensions.Render[TModel](WebViewPage`1 view, HttpContextBase httpContext, TModel model)
   at RazorGenerator.Testing.WebViewPageExtensions.RenderAsHtml[TModel](WebViewPage`1 view, HttpContextBase httpContext, TModel model)
   at RazorGenerator.Testing.WebViewPageExtensions.RenderAsHtml[TModel](WebViewPage`1 view, TModel model)
Coordinator
Jun 14, 2013 at 12:58 AM
There is both a test that uses Model and one that uses ViewBag and they both work. Note that you're not supposed to set view.ViewData.Model, but instead you should pass the model as a param to RenderAsHtml. Can you try that?
Jun 14, 2013 at 2:04 AM
Hrmm... ok, tried this (removed the ViewContext initialization as well).
            var view = new HomePage();
            
            HtmlDocument doc = view.RenderAsHtml(new HomePageModel(content, x, false));
I'm now back to the original exception on InitHelpers:
System.ArgumentNullException: Value cannot be null.
Parameter name: viewContext
    at System.Web.Mvc.AjaxHelper..ctor(ViewContext viewContext, IViewDataContainer viewDataContainer, RouteCollection routeCollection)
   at System.Web.Mvc.AjaxHelper`1..ctor(ViewContext viewContext, IViewDataContainer viewDataContainer, RouteCollection routeCollection)
   at System.Web.Mvc.WebViewPage.InitHelpers()
   at System.Web.Mvc.WebViewPage`1.InitHelpers()
   at Microsoft.Wps.Consumer.Web.Global.ConsumerWebViewPage`1.InitHelpers() in ConsumerWebViewPage.cs: line 103
   at System.Web.Mvc.WebViewPage`1.get_ViewData()
   at RazorGenerator.Testing.WebViewPageExtensions.Initialize(WebViewPage`1 view, HttpContextBase httpContext)
   at RazorGenerator.Testing.WebViewPageExtensions.Render(WebViewPage`1 view, HttpContextBase httpContext, TModel model)
   at RazorGenerator.Testing.WebViewPageExtensions.RenderAsHtml(WebViewPage`1 view, HttpContextBase httpContext, TModel model)
   at RazorGenerator.Testing.WebViewPageExtensions.RenderAsHtml(WebViewPage`1 view, TModel model)
I notice there's another overload where you pass in an HttpContext... wonder if that would work better for me?
Jun 14, 2013 at 2:13 AM
Hrmm, no. That didn't seem to work either...
Jun 14, 2013 at 4:23 AM
I think I've found where the problem is, but I'm not sure how it should be fixed...

The first thing called in RazorGenerator.Testing.WebViewPageExtensions.Render is Initialize. After that you set the model...

But in Initialize, you create a ViewContext, and pass ViewData into that, but that's going to be null and throws an exception.

I actually had an issue before this but was able to work around it. This one, I'm not sure about...
Coordinator
Jun 14, 2013 at 5:06 AM
I'll really need a repro here in order to investigate, since I don't see this with my scenario.

Also, as a test, what happens for you if you just write:
            var view = new HomePage();
            
            var viewData = view.ViewData;
Does it blow up on the ViewData access? If so, at least we've isolated away from the RenderAsHtml call.
Jun 14, 2013 at 5:10 AM
David, I'd be happy to work more closely with you offline if you like. We could get a repro and I can try to get a fix. You can find me in the GAL.

Thanks
Matt Fraser
Coordinator
Jun 14, 2013 at 5:45 AM
Sure, feel free to email me a repro. The simpler the better! :)
Oct 10, 2013 at 2:07 AM
Hi,

I've got the same problem. Does this have a solution yet?

Many thanks

Jiazi
Coordinator
Oct 10, 2013 at 5:52 PM
I didn't get a repro, so no change since above.
Nov 20, 2013 at 7:34 PM
Edited Nov 20, 2013 at 7:42 PM
I have a repro case, toss me a line if you want code.

I installed the Razor Generator VS plugin in VS2012
In VS 2012 I created a new ASP.net MVC 4 project.
I then created a test project in the same solution
I included the MVC project as a reference for the test project
I added the RazorGenerator.mvc nuget package to the MVC project
I added the RazorGenerator.Testing nuget package to the test project

I wrote this test:
namespace UnitTestingViews.Tests
{
    [TestClass]
    public class UnitTest1
    {
        [TestMethod]
        public void TestMethod1()
        {
            var view = new Index();
            Assert.IsNotNull(view.RenderAsHtml());
        }
    }
}
I got this error when running the test:
Test method UnitTestingViews.Tests.UnitTest1.TestMethod1 threw exception: 
System.ArgumentNullException: Value cannot be null.
Parameter name: viewContext
    at System.Web.Mvc.AjaxHelper..ctor(ViewContext viewContext, IViewDataContainer viewDataContainer, RouteCollection routeCollection)
   at System.Web.Mvc.AjaxHelper`1..ctor(ViewContext viewContext, IViewDataContainer viewDataContainer, RouteCollection routeCollection)
   at System.Web.Mvc.WebViewPage.InitHelpers()
   at System.Web.Mvc.WebViewPage`1.InitHelpers()
   at System.Web.Mvc.WebViewPage`1.get_ViewData()
   at RazorGenerator.Testing.WebViewPageExtensions.Initialize(WebViewPage`1 view, HttpContextBase httpContext)
   at RazorGenerator.Testing.WebViewPageExtensions.Render(WebViewPage`1 view, HttpContextBase httpContext, TModel model)
   at RazorGenerator.Testing.WebViewPageExtensions.RenderAsHtml(WebViewPage`1 view, HttpContextBase httpContext, TModel model)
   at RazorGenerator.Testing.WebViewPageExtensions.RenderAsHtml(WebViewPage`1 view, TModel model)
   at UnitTestingViews.Tests.UnitTest1.TestMethod1() in UnitTest1.cs: line 15
Coordinator
Nov 21, 2013 at 1:27 AM
Yes, please share your repro as Github repo. Note that my test app has a very similar test and it works fine. Not sure the difference.
Coordinator
Nov 21, 2013 at 1:34 AM
I just tried with a branch new MVC4 app with your steps above and didn't see the issue. Must be some minor difference somewhere.
Nov 21, 2013 at 4:41 PM
https://github.com/Ben-A10U8/TestingViewsTest

Dunno how Github allowed bstarbird to commit to that, but whatevs, yay for global .gitconfigs :)
Coordinator
Nov 21, 2013 at 5:56 PM
Thanks! And did you check whether the tests work for you in my test app above? If they don't, then it's possible we're dealing with some environment issue that is not caused by something specific that your test app is doing.
Nov 21, 2013 at 6:08 PM
Greetings Guys,

I am still facing this issue 'Value cannot be null.Parameter name: viewContext'. Here are my steps to reproduce:
  1. Windows 7 64 bit, Visual Studio 2012
  2. Open new MVC4 Internet Application with Unit Test project
  3. Include RazorGenerator.Mvc.2.2.1 package into MainApplication
  4. Include RazorGenerator.Testing.2.1.1 package into TestApplication
  5. Set the Views/Home/Index.cshtml property CustomTool to RazorGenerator, it will create Index.generated.cs file.
  6. Add MainApplication reference into TestApplication
  7. Create a ViewTest unit test in the TestApplication, and add the following code: The error happens at the line 'view.Render();'
       const string message = "Some unit test message!";
        // Instantiate the view directly
        var view = new MvcApplication1.Views.Home.Index();
        // Set up the data that needs to be access by the view
        view.ViewBag.Message = message;
        // Render it in an HtmlDocument
        string output = view.Render();
        // Verify that it looks correct
        Assert.IsTrue(output.Contains(message));
    
Please help me out
Nov 21, 2013 at 6:20 PM
I have found a way to solve my issue. In th beginning, I have a test like below:
         var view = new Index();

         view.ViewBag.Message = "X";

         var model = new BookViewModel();
                        
         HtmlDocument output = view.RenderAsHtml(model);
And I have got System.NullReferenceException.

Then I have tried passing a "Fully Populated" model (all fields used in the View) to the view, it works!!
            var view = new Index();

            view.ViewBag.Message = "X";

            var model = new BookViewModel();

            // populate the model
            model.MyFavouriteBookName = "Gone with the wind";
            model.MyTotalBookCount = 100;
            model.MyLastBookName = "Harry Potter";
            model.MyDocuments = new List<MyDocument>();
            var doc = new MyDocument { DocumentName = "X" };
            model.MyDocuments.Add(doc);
            doc = new MyDocument { DocumentName = "Y" };
            model.MyDocuments.Add(doc);

            // Render it as a string            
            HtmlDocument output = view.RenderAsHtml(model);
Hope this could help some of you

Cheers
Nov 21, 2013 at 6:48 PM
davidebbo wrote:
Thanks! And did you check whether the tests work for you in my test app above? If they don't, then it's possible we're dealing with some environment issue that is not caused by something specific that your test app is doing.
Your test project works. I'll start checking what dependencies have changed between yours and mine.
Coordinator
Nov 21, 2013 at 6:54 PM
@yueyinsq: In @Ben's case he's not passing a model at all, so it's probably not quite the same thing. Ben, I do repro the issue with your repo, though at this point I can't explain the difference.
Nov 21, 2013 at 7:14 PM
I have downloaded this test project and tested, still fails on my end.
Nov 21, 2013 at 7:15 PM
davidebbo wrote:
Yes, please share your repro as Github repo. Note that my test app has a very similar test and it works fine. Not sure the difference.
I have downloaded this test project and tested, still fails on my en
Coordinator
Nov 21, 2013 at 7:17 PM
Which test project? There is https://github.com/davidebbo/MvcApplicationRazorGeneratorSeparateLibrary and https://github.com/Ben-A10U8/TestingViewsTest. The first one works for me and the second fails.
Nov 21, 2013 at 7:25 PM
@davidebbo. Both are failed on my end
Nov 21, 2013 at 7:52 PM
davidebbo wrote:
@yueyinsq: In @Ben's case he's not passing a model at all, so it's probably not quite the same thing. Ben, I do repro the issue with your repo, though at this point I can't explain the difference.
I took a look at the differences and I see nothing. I updated Moq and RazorGenerator.Testing to the newest versions in MvcApplicationRazorGeneratorSeparateLibrary and still worked. Then I just ran update-package in package manager console to update everything and it still ran fine.

I'm not sure where to look next.
Coordinator
Nov 21, 2013 at 8:31 PM
I found the issue. The root of the problem is that RazorGenerator is built against MVC3, and it needs Binding Redirects to work with MVC4.

I sent a pull request on your test project to show exactly what needs to be changed.

@slagadapati: if both are failing for you, you are likely dealing with something unrelated.
Nov 21, 2013 at 8:56 PM
@davidebbo: Are these packages are correct versions? RazorGenerator.Mvc.2.2.1, RazorGenerator.Testing.2.1.1
Nov 21, 2013 at 9:00 PM
@davidebbo: That indeed did it. I'll leave the repo up for when people run into the issue in the future.

I had noticed that your test project had the binding redirects when I updated Moq, but I didn't see the significance.

Note for people in the future: Those binding redirects need to be updated for MVC 5 and beyond, as well.

Thanks!
Nov 22, 2013 at 12:00 AM
@davidebbo: I have re-installed my VS2012 ultimate and tested this app https://github.com/davidebbo/MvcApplicationRazorGeneratorSeparateLibrary, it works. But my sample application not working, it gives same error "Value cannot be null.Parameter name: viewContext"
Coordinator
Nov 22, 2013 at 12:02 AM
@slagadapati are you sure that you don't have the same issue as Ben has (see above)?
Nov 23, 2013 at 1:05 AM
@davidebbo: Finally it is started working. Thank you very much