views:

82

answers:

3

I am using a helper in my controllers and in my views that I have found somewhere on the internet. The helper is called like this in my controller "Url.SiteRoot();" How can I get my controller to not throw an Exception whenever the helper is called? I am using MVCContrib and moq for my unit tests.

I am thinking of implementing some kind of a check in the helper but it feel like the MVCContrib framework or the moq should be able to handle this so that I don't need to add Exception code in my helpers just to be able to pass the unit tests.

You can see the Helper code here:-

namespace System.Web.Mvc {
public static class UrlHelpers {

    public static string SiteRoot(HttpContextBase context) {
        return SiteRoot(context, true);
    }

    public static string SiteRoot(HttpContextBase context, bool usePort) {
        var Port = context.Request.ServerVariables["SERVER_PORT"];
        if (usePort) {
            if (Port == null || Port == "80" || Port == "443")
                Port = "";
            else
                Port = ":" + Port;
        }
        var Protocol = context.Request.ServerVariables["SERVER_PORT_SECURE"];
        if (Protocol == null || Protocol == "0")
            Protocol = "http://";
        else
            Protocol = "https://";

        var appPath = context.Request.ApplicationPath;
        if (appPath == "/")
            appPath = "";

        var sOut = Protocol + context.Request.ServerVariables["SERVER_NAME"] + Port + appPath;
        return sOut;

    }

    public static string SiteRoot(this UrlHelper url) {
        return SiteRoot(url.RequestContext.HttpContext);
    }


    public static string SiteRoot(this ViewPage pg) {
        return SiteRoot(pg.ViewContext.HttpContext);
    }

    public static string SiteRoot(this ViewUserControl pg) {
        var vpage = pg.Page as ViewPage;
        return SiteRoot(vpage.ViewContext.HttpContext);
    }

    public static string SiteRoot(this ViewMasterPage pg) {
        return SiteRoot(pg.ViewContext.HttpContext);
    }

    public static string GetReturnUrl(HttpContextBase context) {
        var returnUrl = "";

        if (context.Request.QueryString["ReturnUrl"] != null) {
            returnUrl = context.Request.QueryString["ReturnUrl"];
        }

        return returnUrl;
    }

    public static string GetReturnUrl(this UrlHelper helper) {
        return GetReturnUrl(helper.RequestContext.HttpContext);
    }

    public static string GetReturnUrl(this ViewPage pg) {
        return GetReturnUrl(pg.ViewContext.HttpContext);
    }

    public static string GetReturnUrl(this ViewMasterPage pg) {
        return GetReturnUrl(pg.Page as ViewPage);
    }

    public static string GetReturnUrl(this ViewUserControl pg) {
        return GetReturnUrl(pg.Page as ViewPage);
    }
}
}
A: 

You've probably realized that the reason you're getting exceptions from your extension methods is due to unimplemented properties or methods on the mocked objects, e.g. Request on HttpContextBase, or RequestContext on UrlHelper.

Take a look at some of the strategies posted here for ideas on how to mock the extension method calls. I personally prefer this strategy, which would have you refactoring your extension methods to bet swappable at runtime.

For example, instead of:

public static class UrlHelperExtensions 
{
    public static string GetReturnUrl(this UrlHelper helper) 
    {
        return // your implementation of GetReturnUrl here
    }

}

You'd have:

public interface IUrlHelperExtensions 
{
    string GetReturnUrl(UrlHelper helper);
}

public static class UrlHelperExtensions
{
    public static IUrlHelperExtensions Extensions(this UrlHelper target)
    {
        return UrlHelperExtensionFactory(target);
    }

    static UrlExtensions 
    {
        UrlHelperExtensionFactory = () => new DefaultUrlHelperExtensionStrategy();
    }

    public static Func UrlHelperExtensionFactory { get; set; }
}   

public DefaultUrlHelperExtensionStrategy : IUrlHelperExtensions 
{
    public string GetReturnUrl(UrlHelper helper) 
    {
        return // your implementation of GetReturnUrl here
    }
}

You'd need to change the way you'd call your extension methods, from urlHelper.GetReturnUrl() to urlHelper.Extensions().GetReturnUrl(), and during unit testing, you can set UrlHelperExtensions.UrlHelperExtensionFactory to a mocked object, but this way, you can control the extension methods' behavior at test time.

Jeremy Frey
A: 

That code looks a little complicated. I think this does the same thing and would be much easier to test. (I'm not sure why it needs to be though.)

public string FullApplicationPath(HttpRequestBase request)
{
    var path = request.Url.AbsoluteUri.Replace(request.Url.AbsolutePath,string.Empty);
    if (!string.IsNullOrEmpty(request.Url.Query))
    {
        path = path.Replace(request.Url.Query, string.Empty);
    }
    return path + request.ApplicationPath;
}
Ryan
A: 

As @Jeremy Frey writes you're getting the exceptions because you're failing to stub/fake some essential parts of the HttpContext.

How about using:

Request.Url.GetLeftPart(System.UriPartial.Authority) 

instead of trying to build the logic for building the url yourself? If I remember correctly it should pick up the protocol and port correctly, as well as any virtual directory, site, etc.

PHeiberg