Насмешка над созданием объекта для юнит-теста - PullRequest
1 голос
/ 22 июля 2009

В настоящее время я выполняю рефакторинг некоторого кода, который выполняет 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 ]

4 голосов
/ 22 июля 2009

Я думаю, что вы на правильном пути с идеей Фабрики, но я бы вставил Фабрику в конструктор класса, а не в качестве параметра метода. Конструктор по умолчанию может создать экземпляр фабрики по умолчанию, если он не предоставлен.

У вас также возникнут некоторые проблемы - например, вам понадобятся реальные идентификаторы входа и пароли в ваших модульных тестах - если вы не исключите методы LogonUserA и DuplicateToken. Я хотел бы предложить тонкую оболочку для реализации интерфейса, который вы также можете вставить в конструктор.

Ниже приведены некоторые основные моменты, показывающие, как начать структурирование.

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 голос
/ 22 июля 2009

Я разработчик Java, но ...

Почему бы не сделать "Фабрику" атрибутом класса, который содержит метод Impersonate?

Атрибут «Фабрика», возможно, «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 голосов
/ 22 июля 2009

Я согласен с tvanfosson о введении фабрики через конструктор (или, возможно, через свойство, если вы считаете фабрику необязательной). Однако, так как вы не слишком довольны этим, я предлагаю вам взглянуть на TypeMock Isolator , который позволит вам довольно необычно насмехаться над экземплярами. Он работает, вводя IL аналогично тому, что делают профилировщики, и позволяет вам использовать макеты без изменения настроек объекта.

0 голосов
/ 22 июля 2009

Я бы создал виртуальный метод Impersonate, который вы могли бы высмеять. Метод Impersonate будет выглядеть следующим образом:


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

    return impersonationContext;
}
...