Как я могу протестировать частные методы с помощью DUnit?
-
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}
Простое решение, которое вряд ли является взломом. Мне часто нужно тестировать частные методы, и эта техника добавляет как можно меньше сложностей.