Unit testing MVC 4 view: How do I mock virtual paths?

Jan 28, 2013 at 10:55 PM

My view uses virtual paths and RG generates calls to WebPageExecutingBase.Href, which, in-turn, looks for HttpRuntime.AppDomainAppVirtualPathObject and throws an HttpException: "The application relative virtual path '~/Content/images/logo.png' cannot be made absolute, because the path to the application is not known.".

How do I mock this away?

Coordinator
Jan 28, 2013 at 11:03 PM

Could you provide more details? What code are you writing, and what is the stack of the error? Thanks!

Jan 29, 2013 at 2:45 PM
Edited Jan 29, 2013 at 2:49 PM

 

Hi David, Thanks for the reply. Please see the details below. I can reproduce the problem with the simplest MVC 4 project.


Exception Message:

Test method RGTest.Tests.IndexTest.PersonIndexViewTest threw exception:
System.Web.HttpException: The application relative virtual path '~/Content/images/logo.png' cannot be made absolute, because the path to the application is not known.

 

Exception Stack Trace:

System.Web.VirtualPath.get_VirtualPathString()
System.Web.VirtualPathUtility.ToAbsolute(String virtualPath)
System.Web.WebPages.UrlUtil.Url(String basePath, String path, Object[] pathParts)
System.Web.WebPages.WebPageExecutingBase.Href(String path, Object[] pathParts)
RGTest.Web.Views.Home.Index.Execute() in c:\users\bpeiris\documents\visual studio 2010\Projects\RGTest\RGTest.Web\Views\Home\Index.generated.cs: line 42
RazorGenerator.Testing.WebViewPageExtensions.Render[TModel](WebViewPage`1 view, HttpContextBase httpContext, TModel model)
RazorGenerator.Testing.WebViewPageExtensions.Render[TModel](WebViewPage`1 view, TModel model)
RGTest.Tests.IndexTest.PersonIndexViewTest() in c:\users\bpeiris\documents\visual studio 2010\Projects\RGTest\RGTest.Tests\IndexTest.cs: line 15

Layout:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width" />
    <title>@ViewBag.Title</title>
    @Styles.Render("~/Content/css")
</head>
<body>
    @RenderBody()
</body>
</html>

View:

<img src="~/Content/images/logo.png" alt="logo"/>
<h2>FooBar</h2>

View result in browser:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width" />
    <title></title>
    <link href="/Content/site.css" rel="stylesheet"/>

</head>
<body>
    <img src="/Content/images/logo.png" alt="logo"/>
<h2>FooBar</h2>

</body>
</html>

View class generated by RG:

 

#pragma warning disable 1591
//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by a tool.
//     Runtime Version:4.0.30319.17929
//
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------

namespace RGTest.Web.Views.Home
{
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using System.Net;
    using System.Text;
    using System.Web;
    using System.Web.Helpers;
    using System.Web.Mvc;
    using System.Web.Mvc.Ajax;
    using System.Web.Mvc.Html;
    using System.Web.Optimization;
    using System.Web.Routing;
    using System.Web.Security;
    using System.Web.UI;
    using System.Web.WebPages;
    
    [System.CodeDom.Compiler.GeneratedCodeAttribute("RazorGenerator", "1.5.0.0")]
    [System.Web.WebPages.PageVirtualPathAttribute("~/Views/Home/Index.cshtml")]
    public class Index : System.Web.Mvc.WebViewPage<dynamic>
    {
        public Index()
        {
        }
        public override void Execute()
        {
WriteLiteral("<img");

WriteAttribute("src", Tuple.Create(" src=\"", 4), Tuple.Create("\"", 35)
, Tuple.Create(Tuple.Create("", 10), Tuple.Create<System.Object, System.Int32>(Href("~/Content/images/logo.png")
, 10), false)
);

WriteLiteral(" alt=\"logo\"");

WriteLiteral("/>\r\n<h2>FooBar</h2>\r\n");

        }
    }
}
#pragma warning restore 1591

MSTest:

Index target = new Index();
var result = target.Render();
Assert.IsTrue(result.Contains("FooBar"));
Coordinator
Jan 29, 2013 at 6:48 PM

I see, it looks like the issue is new to WebPages 2.0, based on some changes they made to the Href logic. The whole RazorGenerator MVC unit test part relies on being able to mock all kind of things, and in this case, it doesn't look like there is an easy way to mock the behavior of WebPageExecutingBase.Href. :(

One workaround might be to use a base type for your views, and add something like that in there:

    public override string Href(string path, params object[] pathParts)
    {
        path = VirtualPathUtility.ToAbsolute(path, "/");
        return base.Href(path, pathParts);
    }

Feb 5, 2013 at 8:04 PM
Sorry, I finally got back to this today.
Your work-around does the trick, thank you very much!