0

I have a MVC 4 controller that makes use of the System.Web.Mvc.HtmlHelper.GenerateLink method. I want to Unit Test the controller and therefore I have to mock this method. I'm using Moq.

My problem is that I get a NullReferenceException when invoking the GenerateLink method and I think this is because I have the first parameter (RequestContext) not mocked properly. But I don't know which properties of the RequestContext I have to mock and how to mock it to get rid of this error.

Currently I have this as setup for the mock:

var RequestContextMock = new Mock<RequestContext>();
RequestContextMock
    .Setup(x => x.HttpContext.Request.ApplicationPath) 
    .Returns(@"/");
RequestContextMock
    .Setup(x => x.HttpContext.Response.ApplyAppPathModifier(It.IsAny<string>()))
    .Returns((string s) => s);

var Routes = new RouteCollection();
Routes.MapRoute(
    name: "Default",
    url: "{controller}/{action}/{id}",
    defaults: new {controller = "Home", action = "Index", id = UrlParameter.Optional});

But that gives the NullReferenceException when the GenerateLink method is executed, so clearly I'm missing some values somewhere.

EDIT: The relevant part of the controller under test is:

public class _AccountInfoController : Controller
{
    readonly IUserRepository _UserRepository;
    readonly IIdentityRepository  _IdentityRepository;

    public _AccountInfoController(IUserRepository userRepository,IIdentityRepository identityRepository)
    {
        this._UserRepository = userRepository;
        this._IdentityRepository = identityRepository;
    }

    [AllowAnonymous]
    public ActionResult Index(RequestContext requestContext, RouteCollection routes)
    {
        var AccountInfoModel = new AccountInfoModel();

        string Email = _IdentityRepository.GetEmailAddress();
        User User = _UserRepository.GetByEmail(Email);
        if (User != null)
        {
            string Link = HtmlHelper.GenerateLink(requestContext,routes,"Logoff",null,"Index","Logoff",null,null);

The Unit Test is:

    [TestMethod]
    public void HaveTenantNameInModel()
    {
        const string TenantName = "tenant name.";
        Tenant TestTenant = new Tenant {Name = TenantName};
        User TestUser = new User {CurrentTenant = (TestTenant)};

        var UserRepository = new Mock<IUserRepository>();
        UserRepository
            .Setup(p => p.GetByEmail(null))
            .Returns(TestUser);

        AccountInfoModel AccountInfoModel = new AccountInfoModel();         

        var IdentityRepository = new Mock<IIdentityRepository>();

        var ControllerUnderTest = new _AccountInfoController(UserRepository.Object,IdentityRepository.Object);

        //Mock the request context
        var RequestContextMock = new Mock<RequestContext>();
        RequestContextMock
            .Setup(x => x.HttpContext.Request.ApplicationPath) 
            .Returns(@"/");
        RequestContextMock
            .Setup(x => x.HttpContext.Response.ApplyAppPathModifier(It.IsAny<string>()))
            .Returns((string s) => s);

        var Routes = new RouteCollection();
        Routes.MapRoute(
            name: "Default",
            url: "{controller}/{action}/{id}",
            defaults: new {controller = "Home", action = "Index", id = UrlParameter.Optional});

        dynamic Result = ControllerUnderTest.Index(RequestContextMock.Object, Routes);

        Assert.IsTrue(Result.GetType() == typeof(PartialViewResult));
        Assert.AreEqual(TenantName, Result.Model.TenantName);
    }
RHAD
  • 1,317
  • 3
  • 13
  • 37
  • Possible duplicate: [Testing HtmlHelpers in ASP.NET MVC](http://stackoverflow.com/questions/271699/testing-htmlhelpers-in-asp-net-mvc). – Sergey Vyacheslavovich Brunov Oct 03 '13 at 18:01
  • Did you try stubbing the Controller Context? Good if you can post the System Under Test as well as the complete Unit Test. var stubContext = new Mock(); and sut.ControllerContext = stubContext.Object – Spock Oct 04 '13 at 03:16
  • Hi Raj, I've posted the Unit test and the controller under test. I'm not sure why and how to stub the controller context. Is this the same as the RequestContext that I use as parameter to the Index action? – RHAD Oct 04 '13 at 06:34

1 Answers1

1

It seems you getting a null reference exception, because your route data setup is missing.

In your Unit Test just before you call the System UnderTest (var ControllerUnderTest = new _AccountInfoController(....), add the line

  RequestContextMock.SetupGet(x => x.RouteData).Returns(new RouteData());

Below is an updated version of your test.

    [TestMethod]
    public void Index_WhenActionExecutes_EnsureReturnModelHasExpectedTenantName() 
    {
        const string expectedTensntName = "tenant name.";
        var fakeTenant = new Tenant { Name = expectedTensntName };
        var fakeUser = new User { CurrentTenant = (fakeTenant) };

        var userRepositoryStub = new Mock<IUserRepository>();
        userRepositoryStub.Setup(p => p.GetByEmail(It.IsAny<string>())).Returns(fakeUser);

        var identityRepositoryStub = new Mock<IIdentityRepository>();
        var sut = new AccountInfoController(userRepositoryStub.Object, identityRepositoryStub.Object);

        var requestContextStub = new Mock<RequestContext>();
        requestContextStub.Setup(x => x.HttpContext.Request.ApplicationPath).Returns(@"/");
        requestContextStub.Setup(x => x.HttpContext.Response.ApplyAppPathModifier(It.IsAny<string>()))
            .Returns((string s) => s);

        var fakeRoutes = new RouteCollection();
        fakeRoutes.MapRoute(name: "Default", url: "{controller}/{action}/{id}",
            defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional });

        requestContextStub.SetupGet(x => x.RouteData).Returns(new RouteData());

        var result = sut.Index(requestContextStub.Object, fakeRoutes) as PartialViewResult;

        Assert.AreEqual(expectedTensntName, ((AccountInfoModel)result.Model).TenantName);
    }
Spock
  • 7,009
  • 1
  • 41
  • 60
  • Thanks Raj, this works fine, I've spent days in this one. And also thank you for making the correction for naming variables etc. I realized that mine were not correctly named and that I have a lot to learn about Unit Testing. – RHAD Oct 04 '13 at 12:27