Доступ к внутренним членам через System.Reflection?
-
05-07-2019 - |
Вопрос
Я пытаюсь выполнить модульное тестирование класса, который имеет множество внутренних функций.Они, очевидно, тоже нуждаются в тестировании, но мой проект «Тесты» является отдельным, главным образом потому, что он охватывает множество небольших взаимосвязанных проектов.Что у меня есть на данный момент:
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, она спросила, что связано с отображением внутренних компонентов тестового проекта.Что ж, сейчас я использую NUnit, и он мне очень нравится, но как я могу добиться с его помощью того же самого?
Решение
Целесообразнее было бы использовать InternalsVisibleTo
атрибут, чтобы предоставить доступ к внутренним членам сборки вашей сборке модульного теста.
Вот ссылка с некоторой полезной дополнительной информацией и пошаговым руководством:
Чтобы ответить на ваш вопрос...Внутренние и защищенные не распознаются в API .NET Reflection.Вот цитата из MSDN:
Ключевые слова C# protected и Internal не имеют значения в IL и не используются в API-интерфейсах Reflection.Соответствующие термины в ИЛ — Семья и Собрание.Чтобы идентифицировать внутренний метод с помощью Reflection, используйте IsAssembly свойство.Чтобы идентифицировать защищенный внутренний метод, используйте IsFamilyOrAssembly.
Другие советы
Добавление InternalsVisibleTo атрибута уровня сборки В вашем основном проекте имя сборки для тестового проекта должно сделать видимыми внутренние элементы.
Например, добавьте следующее в свою сборку вне любого класса:
[assembly: InternalsVisibleTo("AssemblyB")]
Или для более точного таргетинга:
[assembly:InternalsVisibleTo("AssemblyB, PublicKey=32ab4ba45e0a69a1")]
Обратите внимание: если сборка вашего приложения имеет строгое имя, ваша тестовая сборка также должна иметь строгое имя.
Я думаю, вам нужно спросить, стоит ли писать модульные тесты для частных методов?Если вы пишете модульные тесты для своих общедоступных методов с «разумным» покрытием кода, разве вы уже не тестируете какие-либо частные методы, которые в результате должны быть вызваны?
Привязка тестов к частным методам сделает тесты более хрупкими.Вы должны иметь возможность изменить реализацию любых частных методов, не нарушая при этом никаких тестов.
Ссылки:
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
В вашем коде отображаются только поля - поэтому я надеюсь, что в нем не будет внутренних элементов, поскольку поля всегда должны быть закрытыми. (С возможным исключением констант.)
Есть ли в ButtonedForm.TitleButton какие-нибудь непубличные поля? Если вы пытаетесь найти внутренние методы , тогда, очевидно, вам нужно вызывать GetMethods
(или GetMembers
), чтобы получить их.
Как и предполагали другие, InternalsVisibleTo
очень удобен для тестирования (и почти исключительно для тестирования!). Что касается того, следует ли вам тестировать внутренние методы - я определенно считаю полезным иметь возможность сделать это. Я не рассматриваю юнит-тестирование как исключительно тестирование черного ящика. Часто, когда вы знаете, что открытая функциональность реализуется с помощью нескольких внутренних методов, связанных простым способом, проще провести тщательное тестирование каждого из внутренних методов и некоторые «псевдоинтеграции». тесты по публичному методу.
Обоснование использования InternalsVisible в моих обстоятельствах. Мы покупаем исходный код в Chart Control. Мы нашли, где нам нужно внести некоторые изменения в этот источник контроля и скомпилировать нашу собственную версию. Теперь, чтобы убедиться, что мы ничего не сломали, нужно написать несколько модульных тестов, которым нужен доступ к некоторым внутренним полям.
Это идеальный случай, когда InternalsVisible имеет смысл.
Мне было интересно, однако, что вы делаете, если у вас нет доступа к источнику? Как вы могли добраться до внутреннего поля? .Net Reflector может видеть этот код, но я думаю, он просто смотрит на IL.