Unit Testing, how to set Thread.CurrentPrincipal and IsAuthenticated

懵懂的女人 提交于 2019-12-07 19:26:31

问题


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

回答1:


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.




回答2:


Do not set principal using Thread.CurrentPrincipal in unit tests. Set it using AppDomain.CurrentDomain.SetThreadPrincipal. This way every thread in unit tests will inherit your principal.

Drawback is that you can set principal using this method only once.




回答3:


You might try using a object mocking framwork like NMock http://msdn.microsoft.com/en-us/magazine/cc163904.aspx



来源:https://stackoverflow.com/questions/27159622/unit-testing-how-to-set-thread-currentprincipal-and-isauthenticated

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!