模拟 ControllerContext.IsChildAction 在 ParentActionViewContext 中抛出异常

Mocking ControllerContext.IsChildAction throws exception in ParentActionViewContext

我在控制器中有一个 ASP.Net MVC 方法:

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

    return PartialView();
}

我模拟了 IsChildAction,所以它 return 是真的。

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

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

但此更改以某种方式反映了 asp.net 机制,该机制现在期望 属性 ControllerContext.ParentActionViewContext 不为空。因此,当在测试中执行 return 语句时,它会抛出 Null 引用,因为此 属性 为空。 我不能嘲笑它,因为它不是虚拟的:/

知道如何为其注入控制器上下文值吗?

您可能必须在 ControllerContext 最小起订量中使用 CallBase = true

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

这样你仍然可以设置 IsChildAction 属性 但是 CallBase 等于 true ControllerContext 的模拟使用 ControllerContext 的真实实现所以 ParentActionViewContext应该在那里。

Edit:

在对 mvc-sources 进行简短检查后,我猜 Null-Reference Exception 可能是由来自 this.RouteData.DataTokens["ParentActionViewContext"] as ViewContext;ParentActionViewContext 引起的。

因此请尝试将 fakeRouteData.DataTokens["ParentActionViewContext"] = fakeViewContext; 添加到您的测试中。

这对我有用:

[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 ...
}

测试 System.Web.Mvc,版本=5.2.3.0.

首先从包管理器控制台安装这个包

install-package Xania.AspNet.Simulator -Version 1.3.9

这两个测试是针对Update方法的每个执行路径。

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