Как я могу проверить частные методы с помощью DUnit?
У меня есть класс, который я тестирую с помощью DUnit.
В нем есть несколько методов: некоторые общедоступные методы и частные методы.
type
TAuth = class(TDataModule)
private
procedure PrivateMethod;
public
procedure PublicMethod;
end;
Чтобы написать unit test для этого класса, я должен сделать все методы общедоступными.
Есть ли другой способ объявить частные методы, чтобы я мог их протестировать, но они не являются общедоступными?
Ответы
Ответ 1
Вам не нужно публиковать их. Защищено будет. Затем вы можете подтипировать класс для модульного тестирования и обработать защищенные методы. Пример:
type
TAuth = class(TDataModule)
protected
procedure MethodIWantToUnitTest;
public
procedure PublicMethod;
end;
Теперь вы можете подтипировать его для вашего unit test:
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;
Однако, если методы, которые вы хотите использовать unit test, так тесно связаны с модулем данных, что небезопасно иметь их что-либо, кроме личного, тогда вам действительно стоит подумать о рефакторинге методов, чтобы отделить код, который должен быть проверен модулем и кодом, который обращается к внутренним данным модуля данных.
Ответ 2
Это немного глупо, но я думаю, что это самый простой и понятный подход. Используйте эту директиву условной компиляции:
{$IfNDef TEST}
private
{$EndIf}
Ваш unit тестовый проект должен определять TEST в project → conditional defines
. Без указания видимости они становятся опубликованными.
Осторожно: если приватная видимость не первая в объявлении класса, она получит предыдущее определение. Более безопасный, но более подробный и менее понятный способ:
private
{$IfDef TEST}
public
{$EndIf}
Это имеет много преимуществ по сравнению с подклассами или другими подходами:
- Никаких дополнительных сложностей: никаких дополнительных классов в вашем коде.
- Никто не может "по ошибке" подкласс и переопределить ваш класс: вы сохраняете свою архитектуру.
- Когда вы говорите, что метод защищен, вы несколько ожидаете, что он будет переопределен. Вы говорите это тем, кто читает ваш код. Защищенный метод, который не должен быть переопределен, может сбить с толку ваших читателей кода, нарушая мой первый принцип программирования: "Код должен быть написан для чтения другими людьми".
- DUnit находится в своем собственном блоке, не включается везде.
- Вы не касаетесь грязного RTTI.
Я думаю, что это более четкое решение и лучше, чем выбранный ответ.
Когда я использую это, я также настраиваю тестовый проект, чтобы поместить объекты сборки в другой каталог основного проекта. Это предотвращает смешивание двоичных файлов с директивой TEST с другим кодом.
Ответ 3
Я рекомендую книгу " Тестовые шаблоны XUnit " Джерарда Месароса:
Тест-специфичный подкласс
Вопрос: Как мы можем сделать код тестируемым, когда нам нужен доступ к закрытому состоянию SUT?
Ответ: Добавьте методы, которые показывают состояние или поведение, необходимое для теста, в подкласс SUT.
... Если тестируемая система (SUT) не была специально разработана для тестирования, мы можем обнаружить, что тест не может получить доступ к состоянию, которое он должен инициализировать или проверить в какой-то момент теста.
В статье также объясняется, когда его использовать и какие риски он несет.
Ответ 4
Поместите код DUnit внутри своего устройства. Затем вы можете получить доступ к чему угодно.
Ответ 5
В целом, когда я попадаю в эту ситуацию, я часто понимаю, что я нарушаю принцип единой ответственности. Конечно, я ничего не знаю о вашем конкретном случае, но MAYBE, что частные методы должны быть в своем классе. TAuth будет иметь ссылку на этот новый класс в частном разделе.
Ответ 6
С Extended RTTI (Delphi 2010 и новее), вызов частных методов через RTTI - это еще один вариант. Это решение также является наилучшим ответом в Как проверить класс с частными методами, полями или внутренними классами?
Ответ 7
{$IFNDEF UNITEST}
private
{$ENDIF}
Простое решение, которое вряд ли является взломом. Мне часто нужно проверять частные методы, и этот метод добавляет как можно меньше осложнений.