Search code examples
c#asp.net-mvcunit-testingmoqurl-helper

UrlHelper class throws null exception in Asp.net mvc


I am developing an Asp.net mvc web application. I am doing Unit Test to my application. I am using Moq to mock objects. I am trying to mock Url helper class. I found this link- asp.net mvc: how to mock Url.Content("~")?. Using that class, I can mock UrlHelper class in unit test.

I created a BaseController like this

public class BaseController : Controller
{
    private IUrlHelper _urlHelper;

    public new IUrlHelper Url
    {
        get { return _urlHelper; }
        set { _urlHelper = value; }
    }
}

Here is the IUrlHelper interface/abstraction

public interface IUrlHelper
{
    string Action(string actionName);
    string Action(string actionName, object routeValues);
    string Action(string actionName, string controllerName);
    string Action(string actionName, RouteValueDictionary routeValues);
    string Action(string actionName, string controllerName, object routeValues);
    string Action(string actionName, string controllerName, RouteValueDictionary routeValues);
    string Action(string actionName, string controllerName, object routeValues, string protocol);
    string Action(string actionName, string controllerName, RouteValueDictionary routeValues, string protocol, string hostName);
    string Content(string contentPath);
    string Encode(string url);
    string RouteUrl(object routeValues);
    string RouteUrl(string routeName);
    string RouteUrl(RouteValueDictionary routeValues);
    string RouteUrl(string routeName, object routeValues);
    string RouteUrl(string routeName, RouteValueDictionary routeValues);
    string RouteUrl(string routeName, object routeValues, string protocol);
    string RouteUrl(string routeName, RouteValueDictionary routeValues, string protocol, string hostName);
}

I mock the Url.Content() in the unit test like this

Mock<IUrlHelper> urlHelperMock = new Mock<IUrlHelper>();
urlHelperMock
    .Setup(x => x.Content(It.IsAny<string>()))
    .Returns<string>(x => "~/" + x);// Mock Content method of Url Helper

Test run successfully and working fine. The problem is I cannot use it in real time application. I mean when I run my app and call Url.Content("path"), it throws null exception.

For example

public class ExampleController : BaseController
{
    public string GetPath()
    {
       return Url.Content("~/Path/To/File");
    }
}

Url.Content in this code throws null exception. It is working fine in unit test. How can I fix that code?


Solution

  • In this case there really isn't a need to abstract the UrlHelper. Just mock up the helper for the test to do what is required.

    For example, assuming

    public class ExampleController : Controller {
        public string GetContent() {
           return Url.Content("~/Path/To/File");
        }
    }
    

    Here is a test that mocks the UrlHelper using moq to work just like in original example

    [TestClass]
    public class UrlHelperTest {
        [TestMethod]
        public void MockUrlHelper() {
            //Arrange            
            var expectedPath = "~/Path/To/File";
            var expectedContent = "<p>Fake content here<p>";
            var urlHelperMock = new Mock<UrlHelper>();
            urlHelperMock
                .Setup(m => m.Content(expectedPath))
                .Returns(expectedContent)
                .Verifiable();
    
            var sut = new ExampleController();
            sut.Url = urlHelperMock.Object; //Set mock UrlHelper        
    
            //Act
            var actualContent = sut.GetContent();
    
            //Assert
            urlHelperMock.Verify();
            Assert.AreEqual(expectedContent, actualContent);
        }
    }
    

    So now the test can be performed and also the framework will populate the necessary controller properties in production because technically nothing was changed from the original framework to custom abstractions.