C# 如何使用最小起订量模拟 Controller.User

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/758066/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-05 00:04:52  来源:igfitidea点击:

How to mock Controller.User using moq

c#asp.net-mvcunit-testingmockingmoq

提问by Eugenio Miró

I have a couple of ActionMethods that queries the Controller.User for its role like this

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

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

acting conveniently on that condition.

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

I'm starting to make tests for these methods with code like this

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

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

    Assert.IsNotNull(index);
}

and that Test Fails because Controller.User is not set. Any idea?

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

采纳答案by John Foster

You need to Mock the ControllerContext, HttpContextBase and finally IPrincipal to mock the user property on Controller. Using Moq (v2) something along the following lines should work.

您需要模拟 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");
    }

Testing the behaviour when the user isn't an admin is as simple as changing the expectation set on the userMock object to return false.

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

回答by Eirik W

Using Moq version 3.1 (and NUnit):

使用 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'");
    }

Notice that there is no need to create mock for HttpContext, Moq supports nesting of properties when setting up the test.

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

回答by Patrick

When using AspNetCore I could not mock the ControllerContextsince I got an exception.

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

Unsupported expression: m => m.HttpContext
Non-overridable members (here: ActionContext.get_HttpContext) may not be used in setup / verification expressions.

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

Instead I had to mock the HttpContextand create a ControllerContextand pass the HttpContextobject along.

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

I did find that mocking claims or response/request objects works as well when using this method.

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

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