Как я могу протестировать частные методы с помощью DUnit?

StackOverflow https://stackoverflow.com/questions/422379

  •  05-07-2019
  •  | 
  •  

Вопрос

У меня есть класс, который я тестирую с помощью DUnit.Он имеет ряд методов, некоторые общедоступные и частные методы.

type
  TAuth = class(TDataModule)
  private
    procedure PrivateMethod;
  public
    procedure PublicMethod;
  end;

Чтобы написать модульный тест для этого класса, мне нужно сделать все методы общедоступными.

Есть ли другой способ объявить частные методы, чтобы я мог их тестировать, но они не были общедоступными?

Это было полезно?

Решение

Вам не нужно делать их публичными. Защищенный сделает. Затем вы можете подтипить класс для модульного тестирования и открыть защищенные методы. Пример:

type
  TAuth = class(TDataModule)
  protected
    procedure MethodIWantToUnitTest;
  public
    procedure PublicMethod;
  end;

Теперь вы можете подтипить его для своего модульного теста:

interface

uses
  TestFramework, Classes, AuthDM;

type
  // Test methods for class TAuthDM
  TestAuthDM = class(TTestCase)
     // stuff
  end;

  TAuthDMTester = class(TAuthDM)
  public
    procedure MethodIWantToUnitTestMadePublic;
  end;

implementation

procedure TAuthDMTester.MethodIWantToUnitTestMadePublic;
begin
  MethodIWantToUnitTest;
end;

Однако, если методы, которые вы хотите использовать для модульного тестирования, работают с модулем данных настолько тесно, что их небезопасно иметь что-то, кроме частного, тогда вам действительно следует подумать о рефакторинге методов, чтобы отделить код, который требует быть проверенным модулем и кодом, который обращается к внутренностям модуля данных.

Другие советы

Это немного хаотично, но я думаю, что это самый простой и понятный подход.Используйте эту директиву условной компиляции:

  {$IfNDef TEST}
  private
  {$EndIf}

Ваш проект модульного тестирования должен определять TEST в project → conditional defines.Без спецификации видимости они публикуются.

Остерегаться:если частная видимость не является первой в объявлении класса, она получит предыдущее определение.Более безопасный, но более подробный и менее понятный способ:

  private
  {$IfDef TEST}
  public
  {$EndIf}

Это имеет много преимуществ по сравнению с созданием подклассов или другими подходами:

  • Никаких дополнительных сложностей:никаких дополнительных классов в вашем коде.
  • Никто не может «ошибочно» создать подкласс и переопределить ваш класс:вы сохраняете свою архитектуру.
  • Когда вы говорите, что метод защищен, вы в некоторой степени ожидаете, что он будет переопределен.Вы говорите это для тех, кто читает ваш код.Защищенный метод, который не следует переопределять, запутает ваших читателей кода, нарушив мой первый принцип программирования: «Код должен быть написан для того, чтобы его могли читать другие люди».
  • DUnit находится в отдельном блоке, не везде включен.
  • Вы не трогаете грязный RTTI.

Я думаю, что это более четкое решение и лучше, чем выбранный ответ.

Когда я использую это, я также настраиваю тестовый проект так, чтобы объекты сборки помещались в другой каталог основного проекта.Это предотвращает смешивание двоичных файлов с директивой TEST с другим кодом.

Я рекомендую " тестовые шаблоны XUnit " книга Джерарда Месароса:

специфичный для теста подкласс

  

Вопрос : как мы можем сделать код   тестируемый, когда нам нужен доступ   частное состояние СУТ?

     

Ответ . Добавьте методы, которые   состояние или поведение, необходимое для теста   в подкласс SUT.

     

... Если тестируемой системы (SUT) не было   разработан специально для тестирования,   мы можем обнаружить, что тест не может получить   доступ к утверждению, что он должен   инициализировать или проверить в какой-то момент   тест.

В статье также объясняется, когда его использовать и какие риски он несет.

Поместите код DUnit в свой блок. Затем вы можете получить доступ ко всему, что вам нравится.

Вообще, попадая в такую ​​ситуацию, я часто понимаю, что нарушаю принцип единой ответственности.Конечно, я ничего не знаю о вашем конкретном случае, но МОЖЕТ БЫТЬ, что частные методы должны быть в своем собственном классе.Тогда TAuth будет иметь ссылку на этот новый класс в своем частном разделе.

В Расширенном RTTI (Delphi 2010 и новее) вызов частных методов через RTTI является еще одним вариантом. Это решение также является самым популярным ответом в Как проверить класс с закрытыми методами, полями или внутренними классами?

{$IFNDEF UNITEST}
private
{$ENDIF}

Простое решение, которое вряд ли является взломом. Мне часто нужно тестировать частные методы, и эта техника добавляет как можно меньше сложностей.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top