Search code examples
c#unit-testingiprincipal

Unit Testing, how to set Thread.CurrentPrincipal and IsAuthenticated


I am trying to perform a unit test of an n-tier application, service layer, repository layer and web api controllers. My repositories are checking the Thread.CurrentPrincipal object to get the current user. This is where I have a problem, when I create the implementation class that inherits from IPrincipal it does allow me to set the IsUserAuthenticated. Is there a way to simulate this for my unit tests. I would like to set the Thread.CurrentPrincipal to my implementation object. How would I simulate a user in this way?

In my RepositoryBase code, I call the following to determine if user is authenticated:

public bool IsUserAuthenticated
{
   get { return ((UserPrincipal)Principal).Identity.IsAuthenticated; }
}

The actual test looks something like:

Contract.Requires<UserAccessException>(IsUserAuthenticated, "Illegal Access.");

I am pulling IsUserAuthenticated from the UserPrincipal below:

namespace HeyLetsTrain.Toolkit.Helper.Authentication
{
    public class UserPrincipal : IPrincipal
    {
        IIdentity _identity;
        string[] _role;
        string _emailAddress;


        public UserPrincipal(string name, string[] role)
        {
            if (role != null) 
            {
                _role = new string[role.Length];
                _role.CopyTo(role, 0);
                Array.Sort(_role);
            }
            _identity = new GenericIdentity(name);
        }

        public IIdentity Identity
        {
            get { return _identity; }
        }

        public string EmailAddress
        {
            get { return _emailAddress; }
            set { this._emailAddress = value; }
        }

        public bool IsInRole(string role)
        {
            return Array.BinarySearch(_role, role) >= 0 ? true : false;
        }

        public bool IsInAllRoles( params string [] roles )
        {
           foreach (string searchrole in roles )
           {
               if (Array.BinarySearch(_role, searchrole) < 0 )
               return false;
           }
           return true;
        }

        public bool IsInAnyRoles( params string [] roles )
        {
            foreach (string searchrole in roles )
            {
                if (Array.BinarySearch(_role, searchrole ) > 0 )
                return true;
            }
           return false;
        }
    }
}

Solution

  • I would wrap Thread.CurrentPrincipal call with a class and then extract the interface. This approach would allow me to pass my dummy implementation as a dependency.

    Another approach is to prepare static class like this:

    public static class ApplicationPrincipal
    {
      private static Func<IPrincipal> _current = () => Thread.CurrentPrincipal;
    
    
      public static IPrincipal Current
      {
          get { return _current(); }
      }
    
      public static void SwitchCurrentPrincipal(Func<IPrincipal> principal)
      {
          _current = principal;
      }
    
    }
    

    Then you have to use ApplicationPrincipal.Current in your repositories instead of direct call. In your tests you will be able to switch default logic by calling ApplicationPrincipal.SwitchCurrentPrincipal(() => myPrincipal).

    Edit:

    I would change:

    public bool IsUserAuthenticated
    {
       get { return ((UserPrincipal)Principal).Identity.IsAuthenticated; }
    }
    

    With:

    public bool IsUserAuthenticated
    {
       get { return ApplicationPrincipal.Current.Identity.IsAuthenticated; }
    }
    

    And then in arrange section of the test I would change default IPrincipal with:

    var principalMock = new UserPrincipal(isAuthenticated: true);
    
    ApplicationPrincipal.SwitchCurrentPrincipal(() => principalMock);
    

    I assume you can somehow overload the value of IsAuthenticated in UserPrincipal object.