Как я могу протестировать частные методы с помощью DUnit? - PullRequest
16 голосов
/ 08 января 2009

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

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

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

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

Ответы [ 7 ]

21 голосов
/ 08 января 2009

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

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;

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

8 голосов
/ 14 сентября 2011

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

  {$IfNDef TEST}
  private
  {$EndIf}

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

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

  private
  {$IfDef TEST}
  public
  {$EndIf}

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

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

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

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

5 голосов
/ 13 марта 2010

Я рекомендую книгу Джерарда Месароса " XUnit Test Patterns ":

Подкласс для конкретного теста

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

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

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

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

4 голосов
/ 07 февраля 2012

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

4 голосов
/ 15 марта 2010

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

2 голосов
/ 24 августа 2014
{$IFNDEF UNITEST}
private
{$ENDIF}

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

2 голосов
/ 15 ноября 2012

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

...