2009-07-22 92 views
1

我目前正在重构一些执行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对象进行的行为?我曾经想过各种替代品:

  • 传递一个工厂类,将创建实例和嘲笑的委托,它
  • 通行证处理该实例的创建行为(即像一个C++函数指针)

没有这些选择似乎特别对我好,因为我怕他们会模糊方法的意图方法签名看起来像下面这样:

public bool Impersonate(string user, string password, string domain, Factory factory) 

public bool Impersonate(string user, string password, string domain, delegate WinIDCreator) 

因为该方法的目的是为了冒充特定的用户,它没有任何意义,我认为无论是工厂类或代表应提供给它。我想要隔离和嘲笑这种行为,但是我对每次运行一堆单元测试时创建的新WindowsIdentity实例的想法感到不自在。

任何想法或意见?

回答

4

我认为你和Factory的想法是正确的,但我会在工厂构造函数中注入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(); 
     ... 
    } 
... 
} 
+0

谢谢你。我应该补充说我已经将登录内容封装到一个NativeMethods类中,并简单地将它们嘲笑出来。担心我将这个工厂注入到类中与使用它作为一个方法参数是一样的 - 让一个类对类工厂有依赖是不自然的...... – jpoh 2009-07-22 03:08:24

0

我会创建一个可以模拟的虚拟模拟方法。该模拟方法是如下:


public virtual WindowsImpersonationContext Impersonate(string tokenDuplicate) { 
    var tempWindowsIdentity = new System.Security.Principal.WindowsIdentity(tokenDuplicate); 
    var impersonationContext = tempWindowsIdentity.Impersonate(); 

    return impersonationContext; 
} 
1

我是一个Java开发,但...

为什么不把“工厂”,它包含了模拟方法的类的属性?

可以在构造函数中或通过setter方法(使用某种类型的依赖注入)设置“Factory”属性,可能是“windowIdentityFactory”。

测试中,您将为模拟工厂提供类(如您所建议的)。在生产中,你给它真正的交易。

... 
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(); 
     ... 
    } 
... 
} 
0

我有关通过构造注射工厂tvanfosson同意(通过属性或可能,如果你把这个工厂可选)。不过,既然你对此不太高兴,我建议你看看TypeMock Isolator,它可以让你以非常规的方式来嘲笑实例。它通过注入类似于探查器所做的IL来工作,它允许您在不改变对象设置的情况下使用模拟。