2

I am trying to run unit tests against a controller decorated with the [Authorize] attribute. The solutions I have found on SO indicate that I should use Moq to mock the authorization. The solution code can be found here.

var controller = new UserController();
var mock = new Mock<ControllerContext>();
mock.SetupGet(x => x.HttpContext.User.Identity.Name).Returns("SOMEUSER");
mock.SetupGet(x => x.HttpContext.Request.IsAuthenticated).Returns(true);
controller.ControllerContext = mock.Object;

I have implemented the above solution in my test:

var controller = new HomeController();
var mock = new Mock<ControllerContext>();
mock.SetupGet(x => x.HttpContext.User.Identity.Name).Returns("SOMEUSER");
mock.SetupGet(x => x.HttpContext.Request.IsAuthenticated).Returns(true);
controller.ControllerContext = mock.Object;

var result = controller.GetStarted();
result.ExecuteResult(mock.Object);
Assert.IsTrue(false); //I am running with a breakpoint here

Result generates, but when I try to execute the result with the mocked controllerContext, I get an error at the line result.ExecuteResul...: NullReferenceException: object instance not set to an instance of an object.

How do I use the mocked ControllerContext to test the controller?

The skeleton code for the controller is:

[Authorize]
public ActionResult GetStarted()
{
    if (User.Identity.IsAuthenticated)
    {
        var user = CommonUtil.Instance.UserManager.FindByName(User.Identity.Name);
        if (user != null)
        {
            ViewBag.IsAdministrator = user.Roles.Contains("Administrators");
            ViewBag.IsActiveUser = user.Roles.Contains("ActiveUsers");
        }
    }
    return View();
}

I have a feeling this is a trivial fix, but I have no idea what I am doing, so it seems impossible.

Community
  • 1
  • 1
Chris
  • 28,822
  • 27
  • 83
  • 158

1 Answers1

1

Ok, figured it out. In case anyone else out there is completely new to Mocking, it really is very easy.

Using the mocking library, you create lambdas that represent calls to certain parts of the object you are mocking. In my case, I needed to mock the object, User.Identity.IsAuthenticated in order to pass through the if statement in the controller.

That simply means that instead of just the code,

var controller = new UserController();
var mock = new Mock<ControllerContext>();
mock.SetupGet(x => x.HttpContext.User.Identity.Name).Returns("SOMEUSER");
mock.SetupGet(x => x.HttpContext.Request.IsAuthenticated).Returns(true);
controller.ControllerContext = mock.Object;

where

mock.SetupGet(x => x.HttpContext.User.Identity.Name).Returns("SOMEUSER");
mock.SetupGet(x => x.HttpContext.Request.IsAuthenticated).Returns(true);

...are your lamdas, simulating the object features HttpContext.User.Identity.Name and HttpContext.Request.IsAuthenticated, respectively, you add the following lamda:

mock.SetupGet(x => x.HttpContext.User.Identity.IsAuthenticated).Returns(true);

This lamda will yield a true in the if statement in the controller code, successfully mocking the criteria needed to pass through the Authorize requirement.

Turns out that my controller requires the user to be on the database...but that error aside, the mocking works to bypass the Authorize decoration and is very easy.

Chris
  • 28,822
  • 27
  • 83
  • 158