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

时间:2009-07-22 02:34:52

标签: c# unit-testing rhino-mocks

我目前正在重构一些执行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)

因为该方法的目的是模仿特定用户,所以对我来说,应该向它提供Factory类或Delegate是没有意义的。我确实希望隔离并模拟这种行为,因为我对每次运行一系列单元测试时创建的新WindowsIdentity实例的想法感到不舒服。

有任何想法或意见吗?

4 个答案:

答案 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,它允许你在不改变对象设置的情况下使用模拟。