繁体   English   中英

单元测试,如何设置Thread.CurrentPrincipal和IsAuthenticated

[英]Unit Testing, how to set Thread.CurrentPrincipal and IsAuthenticated

我正在尝试对n层应用程序,服务层,存储库层和Web api控制器执行单元测试。 我的存储库正在检查Thread.CurrentPrincipal对象以获取当前用户。 这是我遇到的问题,当我创建从IPrincipal继承的实现类时,确实允许我设置IsUserAuthenticated。 有没有一种方法可以针对我的单元测试进行模拟。 我想将Thread.CurrentPrincipal设置为我的实现对象。 我将如何以这种方式模拟用户?

在我的RepositoryBase代码中,我调用以下命令以确定用户是否已通过身份验证:

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

实际测试如下所示:

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

我从下面的UserPrincipal中提取IsUserAuthenticated:

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

我将使用类包装Thread.CurrentPrincipal调用,然后提取接口。 这种方法将允许我将虚拟实现作为依赖项传递。

另一种方法是准备静态类,如下所示:

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

}

然后,您必须在存储库中使用ApplicationPrincipal.Current而不是直接调用。 在测试中,您将能够通过调用ApplicationPrincipal.SwitchCurrentPrincipal(()=> myPrincipal)来切换默认逻辑。

编辑:

我会改变:

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

附:

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

然后在测试的“安排”部分中,我将使用以下方式更改默认的IPrincipal:

var principalMock = new UserPrincipal(isAuthenticated: true);

ApplicationPrincipal.SwitchCurrentPrincipal(() => principalMock);

我假设您可以以某种方式重载UserPrincipal对象中IsAuthenticated的值。

不要在单元测试中使用Thread.CurrentPrincipal设置主体。 使用AppDomain.CurrentDomain.SetThreadPrincipal进行设置。 这样,单元测试中的每个线程都将继承您的主体。

缺点是只能使用此方法设置一次主体。

您可以尝试使用对象模拟框架,例如NMock http://msdn.microsoft.com/en-us/magazine/cc163904.aspx

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM