代码之家  ›  专栏  ›  技术社区  ›  jpoh

模拟单元测试对象的实例化

  •  1
  • jpoh  · 技术社区  · 17 年前

    我目前正在重构一些代码,这些代码执行Windows模拟以实现可测试性,并且遇到了一些障碍。这就是我遇到问题的代码:

    ...
    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 回复  |  直到 17 年前
        1
  •  4
  •   tvanfosson    17 年前

    我认为您对工厂的想法是正确的,但是我将在类构造函数中注入工厂,而不是作为方法参数。如果未提供默认工厂的实例,则默认构造函数可以创建该实例。

    如果不考虑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();
            ...
        }
    ...
    }
    
        2
  •  1
  •   les2    17 年前

    我是爪哇开发者,但是…

    为什么不使“工厂”成为包含模拟方法的类的属性?

    “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();
            ...
        }
    ...
    }
    
        3
  •  0
  •   jamesaharvey    17 年前

    我将创建一个虚拟的模拟方法,您可以模仿它。模拟方法如下:

    
    public virtual WindowsImpersonationContext Impersonate(string tokenDuplicate) {
        var tempWindowsIdentity = new System.Security.Principal.WindowsIdentity(tokenDuplicate);  
        var impersonationContext = tempWindowsIdentity.Impersonate();
    
        return impersonationContext;
    }
    
        4
  •  0
  •   Brian Rasmussen    17 年前

    我同意Tvanfosson关于通过建造商注入工厂的意见(如果您认为工厂是可选的,也可以通过一个财产注入)。不过,既然你对此不太满意,我建议你看看 TypeMock Isolator 这将让您以一种非常非常规的方式模拟实例。它的工作原理是注入类似于配置程序所做的IL,它允许您在不更改对象设置的情况下使用模拟。