Why is Controller.Url null when I unit test my action?

眉间皱痕 提交于 2020-01-03 15:32:10

问题


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();
    }
 }

回答1:


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.



来源:https://stackoverflow.com/questions/9828220/why-is-controller-url-null-when-i-unit-test-my-action

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!