How to mock Controller.User using moq

后端 未结 3 1417
陌清茗
陌清茗 2020-12-05 03:57

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

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

acting co

相关标签:
3条回答
  • 2020-12-05 04:35

    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.

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

    0 讨论(0)
  • 2020-12-05 04:39

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

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

    Instead I had to mock the HttpContext and create a ControllerContext and pass the HttpContext object along.

    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);
    }
    
    0 讨论(0)
  • 2020-12-05 04:57

    Using Moq version 3.1 (and 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.

    0 讨论(0)
提交回复
热议问题