18

I'm trying to figure out a way to inspect a razor view's rendered HTML within a test.

I've been looking at posts where people have asked similar questions, but each time, I fall short. The problem I'm getting is when the view engine tries to load the .cshtml file. It's returning a null reference exception from within the function.

[Test]
public void GetRazorViewEngine() {
    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 routeData = new RouteData();
    routeData.Values.Add("controller", "Home");
    routeData.Values.Add("action", "About");

    var controller = new HomeController();
    controller.ControllerContext = new 
    ControllerContext(_HttpContextBaseMock.Object,
                      routeData,
                      controller);
    controller.Url = new UrlHelper(new RequestContext(_HttpContextBaseMock.Object, routeData),
                                   new RouteCollection());


    var razorEngine = ViewEngines.Engines
                                 .Where(x => x.GetType() == typeof(System.Web.Mvc.RazorViewEngine))
                                 .FirstOrDefault();

    var path = "/Users/dan/Projects/Playground/MvcPlayground/Views/Home/About.cshtml";
    var master = "/Users/dan/Projects/Playground/MvcPlayground/Views/Shared/_Layout.cshtml";

    ViewEngineResult viewEngineResult = razorEngine.FindView(controller.ControllerContext,
                                                             path,
                                                             master,
                                                             false);
}

Here is the stack trace of the error.

at System.Web.WebPages.FileExistenceCache.<.ctor>b__4 (System.String path) <0x3880c90 + 0x00022> in :0 at System.Collections.Concurrent.ConcurrentDictionary2[TKey,TValue].GetOrAdd (System.Collections.Concurrent.TKey key, System.Func2 valueFactory) [0x00037] in /private/tmp/source-mono-4.4.0-c7sr0/bockbuild-mono-4.4.0-branch-c7sr0/profiles/mono-mac-xamarin/build-root/mono-x86/external/referencesource/mscorlib/system/collections/Concurrent/ConcurrentDictionary.cs:1049 at System.Web.WebPages.FileExistenceCache.FileExists (System.String virtualPath) <0x3880880 + 0x0003f> in :0 at System.Web.Mvc.BuildManagerViewEngine.FileExists (System.Web.Mvc.ControllerContext controllerContext, System.String virtualPath) <0x38807f8 + 0x0001f> in :0 at System.Web.Mvc.VirtualPathProviderViewEngine.GetPathFromSpecificName (System.Web.Mvc.ControllerContext controllerContext, System.String name, System.String cacheKey, System.String[]& searchedLocations) <0x369b9f8 + 0x00039> in :0 at System.Web.Mvc.VirtualPathProviderViewEngine.GetPath (System.Web.Mvc.ControllerContext controllerContext, System.String[] locations, System.String[] areaLocations, System.String locationsPropertyName, System.String name, System.String controllerName, System.String cacheKeyPrefix, Boolean useCache, System.String[]& searchedLocations) <0x369af00 + 0x0033b> in :0 at System.Web.Mvc.VirtualPathProviderViewEngine.FindView (System.Web.Mvc.ControllerContext controllerContext, System.String viewName, System.String masterName, Boolean useCache) <0x369aa30 + 0x000b7> in :0 at MvcPlayground.Tests.HomeControllerTest.GetRazorViewEngine () [0x00163] in /Users/dan/Projects/Playground/MvcPlayground.Tests/Controllers/HomeControllerTest.cs:82 at (wrapper managed-to-native) System.Reflection.MonoMethod:InternalInvoke (System.Reflection.MonoMethod,object,object[],System.Exception&) at System.Reflection.MonoMethod.Invoke (System.Object obj, BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) [0x00038] in /private/tmp/source-mono-4.4.0-c7sr0/bockbuild-mono-4.4.0-branch-c7sr0/profiles/mono-mac-xamarin/build-root/mono-x86/mcs/class/corlib/System.Reflection/MonoMethod.cs:295

CSDev
  • 3,177
  • 6
  • 19
  • 37
Dan Champagne
  • 890
  • 2
  • 17
  • 37
  • 2
    Did you ever figure out a solution to this? – tamj0rd2 Mar 21 '19 at 10:38
  • While im not entirely sure if this will help you, you can use global filters in your mvc application to insert login into any part of the MVC pipeline. https://learn.microsoft.com/en-us/dotnet/api/system.web.mvc.actionfilterattribute?view=aspnet-mvc-5.2 Specifically you can use the System.Web.Mvc.ResultExecutedContext.HttpContext.Response to look at the result of your razor rendering. In practice I am unsure if this can be used in unit tests. – Taylor Apr 03 '19 at 21:57
  • Did You resolve the problem? I have similar problem and in my case the problem is that in `HttpContextBase` you have to return some `Cache`, I didt resolve yet how to do it, this doesnt work `_HttpContextBaseMock .Setup(x => x.Cache).Returns(new System.Web.Caching.Cache());` Edit: Damn, 3 years ... – user0810 Dec 12 '19 at 18:56
  • 3
    why are you even trying this? A unit test should not even try to access files on disk – Andrei Dragotoniu Oct 22 '20 at 06:55
  • I am not seeing the .cshtml file being loaded in any where. I take it that RazorEngine.FindView is supposed to do that? Or what do you mean when you say "returning a null reference exception"? I'm assuming you mean that a null reference exception was thrown within the given function, but perhaps you mean that the function set a particular value to null, causing the exception to be thrown later. A void cannot literally return a null reference exception. – Caston Sep 14 '21 at 22:30

1 Answers1

1

Look at (Razor engine cant find view) also note that RazorViewEngine's had some problems with pre-compiled views in the past: https://github.com/aspnet/Mvc/issues/6672. However, It looks to me like RazorViewEngine has changed a little bit within the past 5 years. I'd say it is time to update and try again.

Caston
  • 144
  • 7