简体   繁体   中英

Mocking ControllerContext.IsChildAction throws exception in ParentActionViewContext

I have an ASP.Net MVC method in controller:

public ActionResult Update()
{
    if(!ControllerContext.IsChildAction)
    {
        return RedirectToAction("Details","Project");
    }

    return PartialView();
}

I mock IsChildAction so it returns true.

var mockControllerContext = new Mock<ControllerContext>(); 
mockControllerContext.SetupGet(m => m.IsChildAction).Returns(true);

YourController controller = new YourController(); 
controller.ControllerContext = mockControllerContext.Object;

But this change somehow reflect to asp.net mechanism which now expects property ControllerContext.ParentActionViewContext is not null. So when return statement is executed in test it throws Null reference because this property is null. I can not mock it because it is not virtual :/

Any idea how to inject in Controller Context value for it?

You would probably have to use CallBase = true in your ControllerContext moq:

var mockControllerContext = new Mock<ControllerContext> { CallBase = true, };

This way you can still setup the IsChildAction property but with CallBase equal to true the mock of ControllerContext uses real implementation of the ControllerContext so the ParentActionViewContext should be there.

Edit:

After a short inspection of mvc-sources i guess that the Null-Reference Exception might be caused by the ParentActionViewContext which comes from: this.RouteData.DataTokens["ParentActionViewContext"] as ViewContext; .

So try to add fakeRouteData.DataTokens["ParentActionViewContext"] = fakeViewContext; to your test.

This worked for me:

[TestMethod]
public void MyTestMethod()
{
    // Arrange
    RouteData fakeRouteData = new RouteData();
    ViewContext fakeViewContext = new ViewContext();
    fakeRouteData.DataTokens["ParentActionViewContext"] = fakeViewContext;

    Mock<HttpContextBase>  httpContextStub = new Mock<HttpContextBase>();
    RequestContext requestContext = new RequestContext(httpContextStub.Object, fakeRouteData);

    HomeController controller = new HomeController();
    var mockControllerContext = new Mock<ControllerContext>(requestContext, controller) { CallBase = true, };
    mockControllerContext.SetupGet(m => m.IsChildAction).Returns(true);

    controller.ControllerContext = mockControllerContext.Object;

    // Act
    var res = controller.Update();

    // Assert
    // TODO ...
}

Tested with System.Web.Mvc, Version=5.2.3.0.

first install this package from Package Manager Console

install-package Xania.AspNet.Simulator -Version 1.3.9

The two tests is for each execution path of the Update method.

[Test]
public void ChildActionNotInvokedAsChildAction()
{
    var action = new TestController()
        .Action(c => c.Update());

    action.GetActionResult().Should().BeOfType<RedirectToRouteResult>();
}

[Test]
public void ChildActionInvokedAsChildAction()
{
    var action = new TestController()
        .ChildAction(c => c.Update());

    action.GetActionResult().Should().BeOfType<PartialViewResult>();
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM