27

My unit tests for an ApiController uses some helpers methods to instantiate the controller:

public static ResourcesController SetupResourcesController(HttpRequestMessage request, IResourceMetadataRepository repo, IUnitOfWorkService unitOfWorkService)
{
    var config = new HttpConfiguration();
    var defaultRoute = config.Routes.MapHttpRoute(RouteNames.DefaultApi , "api/{controller}/{id}");
    var routeData = new HttpRouteData(defaultRoute, new HttpRouteValueDictionary { { "controller", "resources" } });

    var resourcesController = new ResourcesController(repo, unitOfWorkService)
    {
        ControllerContext = new HttpControllerContext(config, routeData, request),
        Request = request
    };
    resourcesController.Request.Properties.Add(HttpPropertyKeys.HttpRouteDataKey, routeData);
    resourcesController.Request.Properties[HttpPropertyKeys.HttpConfigurationKey] = config;

    // Compilation fail: The Property 'System.Web.Http.ApiController.User' has no setter.
    resourcesController.User = myStubUserPrincipal;

    return resourcesController;
}

My question is: how to set the User property for the controller?

I've tried:

request.Properties.Add("MS_UserPrincipal", myStubUserPrincipal);

But this doesn't work either (the resourcesController.User property remains null).

Ralph Willgoss
  • 11,750
  • 4
  • 64
  • 67
JTech
  • 3,420
  • 7
  • 44
  • 51

2 Answers2

37

Set the Thread.CurrentPrincipal, and that will initialize the User property in the controller automatically.

For people that see this answer, but have no idea how to set CurrentPrincipal.: This code is extracted from MSDN.

Thread.CurrentPrincipal = new GenericPrincipal
(
   new GenericIdentity("Bob", "Passport"),
   new[] {"managers", "executives"}
);
Ralph Willgoss
  • 11,750
  • 4
  • 64
  • 67
Pablo Cibraro
  • 3,769
  • 3
  • 25
  • 17
  • Thanks Pablo! Seems too simple to be true but yes; setting the Thread.CurrentPrincipal property within my test setup code did the trick! – JTech Mar 19 '13 at 15:59
  • Great! I was searching on how to mock/fake everything and this is a simple way to do it. – AlignedDev Jun 05 '13 at 15:27
  • 3
    For people that see this answer, but have no idea how to set CurrentPrincipal. This code is extracted from MSDN. Thread.CurrentPrincipal = new GenericPrincipal(new GenericIdentity("Bob", "Passport"), new[] {"managers", "executives"}); http://msdn.microsoft.com/en-us/library/system.threading.thread.currentprincipal.aspx Add this to your answer if you want. – ruffen Sep 19 '13 at 12:24
  • 1
    I tried to use this method in my unit tests for Web Api 2, but the User property is always null. – ozstudent Jun 11 '14 at 05:39
  • This works in Web Api 2 but you need to use "RequestContext.Principal.Identity.Name" to get the current user logged in, this works for unit testing and runtime aswell. – RolandoCC May 06 '15 at 18:56
  • How do you get the User property to have the right value. I am using it in the actual controllers, so the test fails because the User is null. – agarcian Aug 10 '15 at 17:15
  • 4
    You can also set it directly on the controller like so: `resourcesController.RequestContext.Principal = new ...` – Nebula Sep 16 '15 at 09:54
  • @Nebula you should post your comment as another answer – user224567893 Mar 11 '20 at 16:36
13

A cleaner way would be to mock away IPrincipal and HttpRequestContext, for example using Moq:

var userMock = new Mock<IPrincipal>();
userMock.Setup(p => p.IsInRole("admin")).Returns(true);
userMock.SetupGet(p => p.Identity.Name).Returns("tester");
userMock.SetupGet(p => p.Identity.IsAuthenticated).Returns(true);

var requestContext = new Mock<HttpRequestContext>();
requestContext.Setup(x => x.Principal).Returns(userMock.Object);

var controller = new ControllerToTest()
{
    RequestContext = requestContext.Object,
    Request = new HttpRequestMessage(),
    Configuration = new HttpConfiguration()
};
Aage
  • 5,932
  • 2
  • 32
  • 57
Stanislav
  • 1,074
  • 1
  • 9
  • 11