5

I've followed this answer to mock HttpContext, Request, Response and User and set Controller.ControllerContext and Controller.Url.

Controller.Url is most definitely not null before calling controller.Index(). However, inside controller.Index(), it is null. It seems very strange. What am I missing?

Here's my test fixture:

[TestFixture]
public class ControllerFixtureBase
{
    private Mock<HttpContextBase> _httpContextMock;
    private RouteCollection _routes;

    [SetUp]
    public void SetUp()
    {
        var requestMock = new Mock<HttpRequestBase>();
        requestMock.SetupGet(x => x.ApplicationPath)
            .Returns("/");
        requestMock.SetupGet(x => x.Url)
            .Returns(new Uri("http://localhost/a", UriKind.Absolute));
        requestMock.SetupGet(x => x.ServerVariables)
            .Returns(new NameValueCollection());

        var responseMock = new Mock<HttpResponseBase>();
        responseMock.Setup(x => x.ApplyAppPathModifier(It.IsAny<string>()))
            .Returns((string url) => url);

        var principalMock = new Mock<IPrincipal>();
        principalMock.SetupGet(p => p.Identity)
            .Returns(new GenericIdentity("testuser"));
        principalMock.Setup(p => p.IsInRole(ApplicationRoles.DataAdmin))
            .Returns(false);

        _httpContextMock = new Mock<HttpContextBase>();
        _httpContextMock.Setup(x => x.User)
            .Returns(principalMock.Object);
        _httpContextMock.Setup(x => x.Request)
            .Returns(requestMock.Object);
        _httpContextMock.SetupGet(x => x.Response)
            .Returns(responseMock.Object);

        _routes = new RouteCollection();
        MvcApplication.RegisterRoutes(_routes);
    }

    protected void PrepareController(Controller controller)
    {
        var requestContext = new RequestContext(_httpContextMock.Object, new RouteData());

        controller.ControllerContext = new ControllerContext(requestContext, controller);
        controller.Url = new UrlHelper(requestContext, _routes);
    }

    [Test]
    public void Index()
    {
        HomeController controller = new HomeController();
        PrepareController(controller);

        Assert.That(controller.Url, Is.Not.Null);
        Assert.That(controller.ViewBag, Is.Not.Null);

        ViewResult viewResult = controller.Index() as ViewResult;

        Assert.That(viewResult, Is.Not.Null);
        Assert.That(viewResult.ViewBag.IndexUrl, Is.EqualTo("/"));
    }
}

And here's my very simple action:

[Authorize]
public class HomeController : Controller
{
    public ActionResult Index()
    {
        ViewBag.Message = "Modify this template to jump-start your ASP.NET MVC application.";

        // System.NullReferenceException : Object reference not set to an instance of an object.
        ViewBag.IndexUrl = Url.Action("Index");

        return View();
    }
 }
Community
  • 1
  • 1
jrummell
  • 42,637
  • 17
  • 112
  • 171

1 Answers1

0

It seems the answer has nothing to do with mocking. Both my MVC and test project were creating using MVC 4 beta. I ran into some weird issues with AuthorizeAttribute so I converted the projects to MVC 3 by creating new projects and moving files around.

I must have had some mismatched references, because when I manually removed all MVC and Web references from both projects and re-added them, the test passed.

jrummell
  • 42,637
  • 17
  • 112
  • 171