51

我有几个 ActionMethods 像这样查询 Controller.User 的角色

bool isAdmin = User.IsInRole("admin");

在这种情况下方便地采取行动。

我开始用这样的代码对这些方法进行测试

[TestMethod]
public void HomeController_Index_Should_Return_Non_Null_ViewPage()
{
    HomeController controller  = new HomePostController();
    ActionResult index = controller.Index();

    Assert.IsNotNull(index);
}

并且该测试失败,因为 Controller.User 未设置。任何的想法?

4

3 回答 3

75

您需要模拟 ControllerContext、HttpContextBase 和最后的 IPrincipal 来模拟 Controller 上的用户属性。使用 Moq (v2) 应该可以使用以下几行。

    [TestMethod]
    public void HomeControllerReturnsIndexViewWhenUserIsAdmin() {
        var homeController = new HomeController();

        var userMock = new Mock<IPrincipal>();
        userMock.Expect(p => p.IsInRole("admin")).Returns(true);

        var contextMock = new Mock<HttpContextBase>();
        contextMock.ExpectGet(ctx => ctx.User)
                   .Returns(userMock.Object);

        var controllerContextMock = new Mock<ControllerContext>();
        controllerContextMock.ExpectGet(con => con.HttpContext)
                             .Returns(contextMock.Object);

        homeController.ControllerContext = controllerContextMock.Object;
        var result = homeController.Index();
        userMock.Verify(p => p.IsInRole("admin"));
        Assert.AreEqual(((ViewResult)result).ViewName, "Index");
    }

测试用户不是管理员时的行为就像更改 userMock 对象上的期望集以返回 false 一样简单。

于 2009-04-16T21:51:00.507 回答
25

使用 Moq 3.1 版(和 NUnit):

    [Test]
    public void HomeController_Index_Should_Return_Non_Null_ViewPage()
    {
        // Assign:
        var homeController = new HomeController();

        Mock<ControllerContext> controllerContextMock = new Mock<ControllerContext>();
        controllerContextMock.Setup(
            x => x.HttpContext.User.IsInRole(It.Is<string>(s => s.Equals("admin")))
            ).Returns(true);
        homeController.ControllerContext = controllerContextMock.Object;

        // Act:
        ActionResult index = homeController.Index();

        // Assert:
        Assert.IsNotNull(index);
        // Place other asserts here...
        controllerContextMock.Verify(
            x => x.HttpContext.User.IsInRole(It.Is<string>(s => s.Equals("admin"))),
            Times.Exactly(1),
            "Must check if user is in role 'admin'");
    }

请注意,不需要为 HttpContext 创建模拟,Moq 在设置测试时支持属性嵌套。

于 2011-07-04T11:10:28.237 回答
12

使用 AspNetCore 时,我无法模拟,ControllerContext因为我遇到了异常。

不支持的表达式:m => m.HttpContext
不可覆盖的成员(这里:ActionContext.get_HttpContext)不能用于设置/验证表达式。

相反,我不得不模拟HttpContext并创建一个ControllerContext并传递HttpContext对象。

我确实发现使用此方法时,模拟声明或响应/请求对象也可以正常工作。

[Test]
public void TestSomeStuff() {
  var name = "some name";

  var httpContext = new Mock<HttpContext>();
  httpContext.Setup(m => m.User.IsInRole("RoleName")).Returns(true);
  httpContext.Setup(m => m.User.FindFirst(ClaimTypes.Name)).Returns(name);

  var context = new ControllerContext(new ActionContext(httpContext.Object, new RouteData(), new ControllerActionDescriptor()));

  var controller = new MyController()
  {
    ControllerContext = context
  };

  var result = controller.Index();
  Assert.That(result, Is.Not.Null);
}
于 2019-10-15T12:16:41.570 回答