我正在尝试对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;
}
}
}
答案 0 :(得分:4)
我会用类包装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(()=&gt; 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的值。
答案 1 :(得分:1)
不要在单元测试中使用Thread.CurrentPrincipal设置主体。使用AppDomain.CurrentDomain.SetThreadPrincipal设置它。这样,单元测试中的每个线程都将继承您的主体。
缺点是您只能使用此方法设置一次。
答案 2 :(得分:0)
您可以尝试使用像NMock这样的模拟框架的对象 http://msdn.microsoft.com/en-us/magazine/cc163904.aspx