我目前正在重构一些执行Windows Impersonation以实现可测试性的代码,并且遇到了一些障碍。这是我遇到问题的一些代码:
...
if (LogonUserA(user, domain, password, LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, ref token) > 0)
{
if (DuplicateToken(token, 2, ref tokenDuplicate))
{
var tempWindowsIdentity = new System.Security.Principal.WindowsIdentity(tokenDuplicate);
var impersonationContext = tempWindowsIdentity.Impersonate();
...
}
...
}
如何模拟实例化WindowsIdentity对象的行为?我想到了各种替代方案:
这些替代方案对我来说似乎都不是特别好,因为我担心它们会模糊方法的意图,因为方法签名看起来像下面这样:
public bool Impersonate(string user, string password, string domain, Factory factory)
或
public bool Impersonate(string user, string password, string domain, delegate WinIDCreator)
因为该方法的目的是模仿特定用户,所以对我来说,应该向它提供Factory类或Delegate是没有意义的。我确实希望隔离并模拟这种行为,因为我对每次运行一系列单元测试时创建的新WindowsIdentity实例的想法感到不舒服。
有任何想法或意见吗?
答案 0 :(得分:4)
我认为你的工作理念是正确的,但是我会在类构造函数中注入Factory而不是作为方法参数。如果未提供默认工厂,则默认构造函数可以创建默认工厂的实例。
如果您没有考虑LogonUserA和DuplicateToken方法,那么您也会遇到一些问题 - 比如在单元测试中需要真正的登录ID和密码。我建议使用一个瘦的包装器来实现一个接口,你也可以在构造函数中注入它。
以下是一些重点介绍如何开始构建它。
public interface ILogonHelpers
{
bool LogonUser( string user, string domain, string password, ref int token );
void DuplicateToken( int token, ref int duplicateToken );
}
public class MyClass
{
public MyClass( ILogonHelper logonHelper, IIdentityFactory factory )
{
this.LogonHelper = logonHelper ?? new DefaultLogonHelper();
this.IdentityFactory = factory ?? new DefaultIdentityFactory();
}
...
if (this.LogonHelper.Logon(user, domain, password, ref token) > 0)
{
if (this.LogonHelper.DuplicateToken(token, ref tokenDuplicate))
{
var tempWindowsIdentity = this.IdentityFactory.CreateIdentity(tokenDuplicate);
var impersonationContext = tempWindowsIdentity.Impersonate();
...
}
...
}
答案 1 :(得分:1)
我是Java开发人员但是......
为什么不将“Factory”作为包含Impersonate方法的类的属性?
“Factory”属性,也许是“windowIdentityFactory”,可以在构造函数中设置,也可以通过setter方法设置(使用某种类型的依赖注入)。
测试中,您将为该类提供模拟工厂(正如您所建议的那样)。在制作中,你给它真正的交易。
...
if (LogonUserA(user, domain, password, LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, ref token) > 0)
{
if (DuplicateToken(token, 2, ref tokenDuplicate))
{
var tempWindowsIdentity = windowIdentityFactory.newInstance(tokenDuplicate);
var impersonationContext = tempWindowsIdentity.Impersonate();
...
}
...
}
答案 2 :(得分:0)
我会创建一个你可以模拟的虚拟Impersonate方法。 Impersonate方法如下:
public virtual WindowsImpersonationContext Impersonate(string tokenDuplicate) {
var tempWindowsIdentity = new System.Security.Principal.WindowsIdentity(tokenDuplicate);
var impersonationContext = tempWindowsIdentity.Impersonate();
return impersonationContext;
}
答案 3 :(得分:0)
我同意tvanfosson关于通过构造函数注入工厂(或者如果您认为工厂是可选的,可能通过属性)。但是,既然你对此不太满意,我建议你看一下TypeMock Isolator,它会让你以一种非常规的方式模拟实例。它的工作原理是注入类似于分析器的IL,它允许你在不改变对象设置的情况下使用模拟。