Я строю библиотеку классов, которая будет иметь несколько открытых и закрытых методов. Я хочу иметь возможность тестировать приватные методы модульно (в основном при разработке, но также это может быть полезно для будущего рефакторинга).
Как правильно это сделать?
.net
unit-testing
tdd
private
Эрик Лабашоски
источник
источник
pre-historic
с точки зрения интернет-лет, но модульное тестирование частных методов теперь легко и просто: Visual Studio создает необходимые классы доступа, когда это необходимо, и предварительно заполнив логику тестов фрагментами, чертовски близкими к тому, что можно пожелать для простых функциональных тестов. Смотрите, например. msdn.microsoft.com/en-us/library/ms184807%28VS.90%29.aspxОтветы:
Если вы используете .net, вы должны использовать InternalsVisibleToAttribute .
источник
#if DEBUG
вокругInternalsVisibleTo
атрибута , чтобы сделать это не относится к коду выпуска?#if RELEASE_TEST
на то,InternalsVisibleTo
что предлагает Майк, и сделать копию своей конфигурации сборки релиза, которая определяетRELEASE_TEST
. Вы можете протестировать свой код релиза с оптимизацией, но когда вы действительно соберете релиз, ваши тесты будут пропущены.Если вы хотите выполнить модульное тестирование частного метода, возможно, что-то не так. Модульные тесты (вообще говоря) предназначены для тестирования интерфейса класса, то есть его открытых (и защищенных) методов. Конечно, вы можете «взломать» решение этой проблемы (даже если просто сделаете методы общедоступными), но вы также можете рассмотреть:
источник
Это может быть бесполезно для тестирования частных методов. Однако мне также иногда нравится вызывать закрытые методы из тестовых методов. Большую часть времени, чтобы предотвратить дублирование кода для генерации тестовых данных ...
Microsoft предоставляет два механизма для этого:
Accessors
Однако этот механизм иногда немного усложняется, когда дело доходит до изменений интерфейса исходного класса. Поэтому в большинстве случаев я избегаю этого.
Класс PrivateObject Другой способ - использовать Microsoft.VisualStudio.TestTools.UnitTesting.PrivateObject.
источник
Я не согласен с философией «вас должно интересовать только тестирование внешнего интерфейса». Это все равно, что сказать, что в автосервисе должны быть только тесты, чтобы увидеть, вращаются ли колеса. Да, в конечном счете, я заинтересован во внешнем поведении, но мне нравятся мои собственные, частные, внутренние тесты, чтобы они были более конкретными и конкретными. Да, если я проведу рефакторинг, мне, возможно, придется изменить некоторые тесты, но если это не масштабный рефакторинг, мне придется изменить только некоторые из них, и тот факт, что другие (неизменные) внутренние тесты все еще работают, является отличным показателем того, что рефакторинг прошел успешно.
Вы можете попытаться охватить все внутренние случаи, используя только общедоступный интерфейс, и теоретически возможно полностью протестировать каждый внутренний метод (или, по крайней мере, каждый существенный), используя общедоступный интерфейс, но вам, возможно, придется стоять на голове, чтобы достичь это и связь между тестовыми примерами, выполняемыми через открытый интерфейс, и внутренней частью решения, которое они предназначены для тестирования, могут быть трудными или невозможными для распознавания. Указав, что отдельные тесты, которые гарантируют, что внутренний механизм работает должным образом, стоят тех незначительных изменений, которые произошли с рефакторингом - по крайней мере, это был мой опыт. Если вам нужно вносить огромные изменения в свои тесты для каждого рефакторинга, то, возможно, это не имеет смысла, но в этом случае, возможно, вам следует полностью переосмыслить свой дизайн.
источник
FooService
что делатьX
, все, о чем вы должны заботиться, это то, что оно действительно делает поX
запросу. Как это происходит, не имеет значения. Если в классе есть проблемы, не обнаруживаемые через интерфейс (маловероятно), это все еще допустимоFooService
. Если это проблема , которая является видимой через интерфейс, тест на публичных членах должен обнаружить его. Все дело в том, что пока колесо правильно вращается, его можно использовать как колесо.PrivMethod
тестом,PubMethod
какие вызовыPrivMethod
должны это выявить? Что происходит, когда вы меняетеSimpleSmtpService
наGmailService
? Внезапно ваши частные тесты указывают на код, который больше не существует или, возможно, работает по-другому и не сможет работать, даже если приложение может работать идеально, как задумано. Если есть сложная обработка, которая применима к обоим отправителям электронной почты, возможно, она должна быть в той,EmailProcessor
которая может использоваться обоими и проверяться отдельно?В тех редких случаях, когда я хотел протестировать закрытые функции, я обычно модифицировал их для защиты, и я написал подкласс с функцией публичной оболочки.
Класс:
Подкласс для тестирования:
источник
Я думаю, что должен быть задан более фундаментальный вопрос: почему вы пытаетесь сначала протестировать приватный метод? Это запах кода, когда вы пытаетесь протестировать закрытый метод через открытый интерфейс этого класса, тогда как этот метод является частным по причине, так как это деталь реализации. Нужно заботиться только о поведении открытого интерфейса, а не о том, как он реализован под прикрытием.
Если я хочу проверить поведение закрытого метода, используя обычные рефакторинги, я могу извлечь его код в другой класс (возможно, с видимостью на уровне пакета, поэтому убедитесь, что он не является частью общедоступного API). Затем я могу проверить его поведение в изоляции.
Продукт рефакторинга означает, что закрытый метод теперь является отдельным классом, который стал соавтором исходного класса. Его поведение станет понятным благодаря собственным модульным тестам.
Затем я могу посмеяться над его поведением при попытке проверить исходный класс, чтобы затем сосредоточиться на проверке поведения открытого интерфейса этого класса, а не на проверке комбинаторного взрыва открытого интерфейса и поведения всех его закрытых методов. ,
Я вижу это аналогично вождению автомобиля. Когда я веду машину, я не еду с поднятым капотом, поэтому я вижу, что двигатель работает. Я полагаюсь на интерфейс, который обеспечивает автомобиль, а именно на счетчик оборотов и спидометр, чтобы знать, что двигатель работает. Я полагаюсь на то, что машина действительно движется, когда я нажимаю педаль газа. Если я хочу проверить двигатель, я могу проверить его изолированно. : D
Конечно, непосредственное тестирование частных методов может быть последним средством, если у вас есть унаследованное приложение, но я бы предпочел, чтобы унаследованный код был реорганизован для обеспечения лучшего тестирования. Майкл Фезерс написал прекрасную книгу на эту тему. http://www.amazon.co.uk/Working-Effectively-Legacy-Robert-Martin/dp/0131177052
источник
Частные типы, внутренние и частные члены таковы по какой-то причине, и часто вы не хотите связываться с ними напрямую. И если вы это сделаете, есть вероятность, что вы сломаетесь позже, потому что нет никакой гарантии, что парни, создавшие эти сборки, сохранят частные / внутренние реализации как таковые.
Но иногда, когда я выполнял некоторые хаки / исследования скомпилированных или сторонних сборок, я сам заканчивал тем, что хотел инициализировать частный класс или класс с закрытым или внутренним конструктором. Или иногда, когда я имею дело с предварительно скомпилированными устаревшими библиотеками, которые я не могу изменить - я заканчиваю тем, что пишу несколько тестов для частного метода.
Так родился AccessPrivateWrapper - http://amazedsaint.blogspot.com/2010/05/accessprivatewrapper-c-40-dynamic.html - это быстрый класс-обертка, который облегчит работу с помощью динамических функций и отражения C # 4.0.
Вы можете создавать внутренние / частные типы, такие как
источник
Ну, вы можете тестировать приватный метод двумя способами
Вы можете создать экземпляр
PrivateObject
класса, синтаксис которого выглядит следующим образомВы можете использовать отражение.
источник
PrivateClass
first и использовать его. stackoverflow.com/questions/9122708/…Я также использовал метод InternalsVisibleToAttribute. Стоит также упомянуть, что, если вы чувствуете себя некомфортно, когда делаете свои ранее частные методы внутренними, чтобы достичь этого, то, возможно, они все равно не должны быть предметом прямых модульных тестов.
В конце концов, вы тестируете поведение своего класса, а не его конкретную реализацию - вы можете изменить последний, не изменяя первый, и ваши тесты все равно должны пройти.
источник
Есть 2 типа частных методов. Статические приватные методы и нестатические приватные методы (методы экземпляра). Следующие 2 статьи объясняют, как выполнить модульное тестирование частных методов с примерами.
источник
MS Test имеет хорошую встроенную функцию, которая делает приватные члены и методы доступными в проекте, создав файл с именем VSCodeGenAccessors
С классами, производными от BaseAccessor
такие как
источник
На CodeProject есть статья, в которой кратко обсуждаются плюсы и минусы тестирования частных методов. Затем он предоставляет некоторый код отражения для доступа к закрытым методам (аналогично коду, представленному Маркусом выше). Единственная проблема, которую я обнаружил в примере, заключается в том, что код не учитывает перегруженные методы.
Вы можете найти статью здесь:
http://www.codeproject.com/KB/cs/testnonpublicmembers.aspx
источник
Объявите их
internal
, а затем используйте,InternalsVisibleToAttribute
чтобы разрешить их сборке тестового модуля.источник
Я склонен не использовать директивы компилятора, потому что они быстро загромождают вещи. Один из способов смягчить это, если они вам действительно нужны, - поместить их в частичный класс и заставить вашу сборку игнорировать этот файл .cs при создании рабочей версии.
источник
Вы не должны в первую очередь тестировать закрытые методы вашего кода. Вы должны тестировать «открытый интерфейс» или API, общедоступные вещи ваших классов. API - это все открытые методы, которые вы предоставляете внешним абонентам.
Причина в том, что, как только вы начинаете тестировать закрытые методы и внутренние компоненты вашего класса, вы связываете реализацию вашего класса (личные вещи) с вашими тестами. Это означает, что когда вы решите изменить детали реализации, вам также придется изменить свои тесты.
По этой причине вам следует избегать использования InternalsVisibleToAtrribute.
Вот большой доклад Иана Купера, который освещает эту тему: Ian Cooper: TDD, где все пошло не так
источник
Иногда бывает полезно протестировать частные объявления. По сути, компилятор имеет только один открытый метод: Compile (string outputFileName, params string [] sourceSFileNames). Я уверен, что вы понимаете, что было бы сложно протестировать такой метод без проверки каждого «скрытого» объявления!
Вот почему мы создали Visual T #: чтобы облегчить тестирование. Это бесплатный язык программирования .NET (совместимый с C # v2.0).
Мы добавили оператор «.-». Это просто ведет себя как "." оператор, за исключением того, что вы также можете получить доступ к любой скрытой декларации из ваших тестов, не меняя ничего в вашем тестируемом проекте.
Взгляните на наш веб-сайт: загрузите его бесплатно .
источник
Я удивлен, что никто еще не сказал этого, но решение, которое я использовал, состоит в том, чтобы создать статический метод внутри класса, чтобы проверить себя. Это дает вам доступ ко всему общему и частному для тестирования.
Кроме того, на языке сценариев (с возможностями OO, такими как Python, Ruby и PHP), вы можете сами выполнить проверку файла при запуске. Хороший быстрый способ убедиться, что ваши изменения ничего не сломали. Это, очевидно, делает масштабируемое решение для тестирования всех ваших классов: просто запустите их все. (Вы также можете сделать это на других языках с помощью void main, которая также всегда выполняет свои тесты).
источник
Я хочу создать четкий пример кода, который вы можете использовать в любом классе, в котором вы хотите протестировать закрытый метод.
В вашем тестовом классе просто включите эти методы, а затем используйте их, как указано.
$ this -> _ callMethod ('_ someFunctionName', массив (param1, param2, param3));
Просто выдайте параметры в том порядке, в котором они отображаются в оригинальной закрытой функции.
источник
Для тех, кто хочет запускать приватные методы без всякой путаницы. Это работает с любой структурой модульного тестирования, использующей только старый добрый Reflection.
Затем в ваших реальных тестах вы можете сделать что-то вроде этого:
источник
MbUnit получил хорошую обертку для этого под названием Reflector.
Вы также можете установить и получить значения из свойств
Относительно "частного теста" я согласен, что .. в идеальном мире. нет смысла делать частные юнит-тесты. Но в реальности вы можете захотеть написать приватные тесты вместо рефакторинга кода.
источник
Reflector
был заменен на более мощныйMirror
в Gallio / MbUnit v3.2. ( gallio.org/wiki/doku.php?id=mbunit:mirror )Вот хорошая статья о модульном тестировании частных методов. Но я не уверен, что лучше сделать приложение специально разработанным для тестирования (это все равно, что создавать тесты только для тестирования) или использовать рефлексию для тестирования. Уверен, большинство из нас выберет второй путь.
источник
На мой взгляд, вам следует только протестировать открытый API вашего classe.
Обнародование метода для его модульного тестирования нарушает инкапсуляцию, раскрывая детали реализации.
Хороший публичный API решает непосредственную задачу клиентского кода и полностью решает эту задачу.
источник
Я использую класс PrivateObject . Но, как упоминалось ранее, лучше избегать тестирования частных методов.
источник
«CC» - это компилятор командной строки в системе, которую я использую.
-Dfoo=bar
делает эквивалент#define foo bar
. Таким образом, эта опция компиляции эффективно меняет все личные вещи на публичные.источник
Вот пример, сначала подпись метода:
Вот тест:
источник
Чтобы сделать это, нужно иметь свой метод
protected
и написать тестовое устройство, которое наследует ваш класс для тестирования. Таким образом, вы не поворачиваете свой методpublic
, но включаете тестирование.источник
1) Если у вас есть унаследованный код, то единственный способ проверить приватные методы - это рефлексия.
2) Если это новый код, то у вас есть следующие варианты:
Я предпочитаю метод аннотации, самый простой и наименее сложный. Единственная проблема заключается в том, что мы увеличили видимость, что, я думаю, не является большой проблемой. Мы всегда должны кодировать интерфейс, поэтому, если у нас есть интерфейс MyService и реализация MyServiceImpl, то у нас могут быть соответствующие тестовые классы MyServiceTest (методы интерфейса тестирования) и MyServiceImplTest (тестировать частные методы). В любом случае все клиенты должны использовать интерфейс таким образом, что хотя видимость приватного метода была увеличена, это не должно иметь большого значения.
источник
Вы также можете объявить его как открытый или внутренний (с InternalsVisibleToAttribute) при сборке в режиме отладки:
Он раздувает код, но будет
private
в сборке релиза.источник
Вы можете сгенерировать тестовый метод для частного метода из Visual Studio 2008. Когда вы создаете модульный тест для частного метода, папка «Ссылки на тест» добавляется в ваш тестовый проект, а средство доступа добавляется в эту папку. Метод доступа также упоминается в логике метода модульного тестирования. Этот метод доступа позволяет вашему модульному тесту вызывать закрытые методы в тестируемом коде. Для подробностей взгляните на
http://msdn.microsoft.com/en-us/library/bb385974.aspx
источник
Также обратите внимание, что InternalsVisibleToAtrribute имеет требование, чтобы ваша сборка имела строгое имя , что создает свой собственный набор проблем, если вы работаете в решении, для которого раньше этого требования не было. Я использую аксессор для тестирования приватных методов. Посмотрите этот вопрос, что в качестве примера этого.
источник
InternalsVisibleToAttribute
это не требует , чтобы ваши сборки сильно названы. В настоящее время я использую его в проекте, где это не так.