Доступ к внутренним членам через System.Reflection?
Я пытаюсь Unit Test класс, который имеет много внутренних функций. Они, очевидно, тоже нуждаются в тестировании, но мой проект "Тесты" является отдельным, главным образом потому, что он охватывает многие небольшие связанные проекты. Что я до сих пор:
FieldInfo[] _fields =
typeof(ButtonedForm.TitleButton).GetFields(
BindingFlags.NonPublic | BindingFlags.Instance |
BindingFlags.DeclaredOnly);
Console.WriteLine("{0} fields:", _fields.Length);
foreach (FieldInfo fi in _fields)
{
Console.WriteLine(fi.Name);
}
Это хорошо выделяет всех частных участников, но не отображает внутренности. Я знаю, что это возможно, потому что, когда я возился с автогенерируемыми тестами, которые Visual Studio может произвести, он спрашивал, что-то делать с отображением внутренних компонентов в проекте Test. Ну, теперь я использую NUnit и очень люблю его, но как я могу достичь с ним того же?
Ответы
Ответ 1
Было бы более целесообразно использовать атрибут InternalsVisibleTo
, чтобы предоставить доступ к внутренним членам сборки к вашей сборке unit test.
Вот ссылка с полезной дополнительной информацией и прогулкой:
Чтобы ответить на ваш вопрос... Внутренние и защищенные не распознаются в .NET Reflection API. Вот цитата из MSDN:
Ключевые слова С#, защищенные и внутренние, не имеют значения в IL и не используются в Reflection API. Соответствующие термины в IL - это Семья и Ассамблея. Чтобы идентифицировать внутренний метод с использованием Reflection, используйте свойство IsAssembly. Чтобы определить защищенный внутренний метод, используйте IsFamilyOrAssembly.
Ответ 2
Добавление атрибута уровня сборки InternalsVisibleTo к вашему основному проекту, при этом имя сборки тестового проекта Assembly должно сделать видимыми внутренние элементы.
Например, добавьте следующее к своей сборке вне любого класса:
[assembly: InternalsVisibleTo("AssemblyB")]
Или для более конкретного таргетинга:
[assembly:InternalsVisibleTo("AssemblyB, PublicKey=32ab4ba45e0a69a1")]
Обратите внимание, что если ваша сборка приложений имеет сильное имя, ваша тестовая сборка также должна быть сильно названа.
Ответ 3
Я думаю, вам нужно спросить, следует ли вам писать модульные тесты для частных методов? Если вы пишете модульные тесты для ваших общедоступных методов, с "разумным" охватом кода, разве вы уже не тестируете какие-либо частные методы, которые нужно вызвать в результате?
Связывание тестов с частными методами сделает тесты более хрупкими. Вы должны иметь возможность изменять реализацию любых частных методов, не нарушая никаких тестов.
работ:
http://weblogs.asp.net/tgraham/archive/2003/12/31/46984.aspx
http://richardsbraindump.blogspot.com/2008/08/should-i-unit-test-private-methods.html
http://junit.sourceforge.net/doc/faq/faq.htm#tests_11
http://geekswithblogs.net/geekusconlivus/archive/2006/07/13/85088.aspx
Ответ 4
В вашем коде отображаются только поля, поэтому я надеюсь, что он не будет показывать никаких внутренних членов, так как поля всегда должны быть частными IMO. (С потенциальным исключением констант.)
Имеет ли ButtonedForm.TitleButton какие-либо не-частные поля? Если вы пытаетесь найти внутренние методы, то, очевидно, вам нужно позвонить GetMethods
(или GetMembers
), чтобы добраться до них.
Как и другие, InternalsVisibleTo
очень удобен для тестирования (и почти исключительно для тестирования!). Что касается того, нужно ли тестировать внутренние методы - я, конечно, считаю полезным, чтобы это можно было сделать. Я не рассматриваю модульное тестирование как эксклюзивное тестирование с помощью "черного ящика". Часто, когда вы знаете, что публичные функции реализованы с использованием нескольких внутренних методов, связанных простым способом, проще провести тщательное тестирование каждого из внутренних методов и некоторых тестов "псевдоинтеграции" для общедоступного метода.
Ответ 5
В моих обстоятельствах оправдано использование InternalsVisible. Мы покупаем исходный код для управления диаграммой. Мы обнаружили, что нам нужно внести некоторые изменения в этот источник управления и скомпилировать нашу собственную версию. Теперь, чтобы убедиться, что мы ничего не сломали, есть некоторые модульные тесты, которые мне нужно написать, чтобы получить доступ к некоторым внутренним полям.
Это идеальный случай, когда смысл InternalsVisible имеет смысл.
Мне было интересно, однако, что вы делаете, если у вас нет доступа к источнику? Как вы могли добраться до внутреннего поля?.Net Reflector может видеть этот код, но я думаю, что он просто смотрит на IL.