Доступ к внутренним членам через System.Reflection? - PullRequest
24 голосов
/ 05 октября 2008

Я пытаюсь провести модульное тестирование класса, который имеет много внутренних функций. Очевидно, что они тоже нуждаются в тестировании, но мой проект «Тесты» является отдельным, главным образом потому, что он охватывает множество небольших связанных проектов. То, что у меня пока есть:

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 и он мне действительно нравится, но как я могу добиться того же с ним?

Ответы [ 5 ]

32 голосов
/ 05 октября 2008

Было бы более целесообразно использовать атрибут InternalsVisibleTo, чтобы предоставить доступ внутренним элементам сборки к сборке тестового модуля.

Вот ссылка с некоторой полезной дополнительной информацией и описанием:

Чтобы ответить на ваш вопрос ... Внутренние и защищенные не распознаются в .NET Reflection API. Вот цитата из MSDN :

Ключевые слова C # защищенные и внутренние не имеют значения в IL и не используются в API Reflection. Соответствующие термины в IL - это семья и собрание. Чтобы определить внутренний метод с помощью Reflection, используйте свойство IsAssembly . Чтобы определить защищенный внутренний метод, используйте IsFamilyOrAssembly .

6 голосов
/ 05 октября 2008

Ваш код показывает только поля - так что я надеюсь, что он не будет показывать никаких внутренних членов, так как поля всегда должны быть закрытыми IMO. (С возможным исключением констант.)

Имеет ли ButtonedForm.TitleButton какие-нибудь непубличные поля? Если вы пытаетесь найти внутренние методы , то, очевидно, вам нужно вызвать GetMethods (или GetMembers), чтобы получить их.

Как и предполагали другие, InternalsVisibleTo очень удобен для тестирования (и почти исключительно для тестирования!). Что касается того, следует ли вам тестировать внутренние методы - я определенно считаю полезным иметь возможность сделать это. Я не рассматриваю модульное тестирование как исключительно тестирование черного ящика. Часто, когда вы знаете, что открытая функциональность реализуется с помощью нескольких внутренних методов, связанных простым способом, проще провести тщательное тестирование каждого из внутренних методов и некоторые тесты «псевдоинтеграции» для открытого метода.

6 голосов
/ 05 октября 2008

Я думаю, вам нужно спросить, должны ли вы писать модульные тесты для частных методов? Если вы пишете модульные тесты для своих открытых методов с «разумным» охватом кода, разве вы уже не тестировали какие-либо частные методы, которые должны вызываться в результате?

Привязка тестов к частным методам сделает тесты более хрупкими. Вы должны иметь возможность изменять реализацию любых частных методов, не нарушая никаких тестов.

Refs:

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

6 голосов
/ 05 октября 2008

Добавление атрибута уровня сборки InternalsVisibleTo к основному проекту с именем сборки в тестовом проекте должно сделать видимыми внутренние элементы.

Например, добавьте следующее к вашей сборке вне любого класса:

[assembly: InternalsVisibleTo("AssemblyB")]

Или для более точного таргетинга:

[assembly:InternalsVisibleTo("AssemblyB, PublicKey=32ab4ba45e0a69a1")]

Обратите внимание: если ваша сборка приложения имеет строгое имя, ваша тестовая сборка также должна иметь строгое имя.

1 голос
/ 04 июня 2009

Обоснование использования InternalsVisible в моих обстоятельствах. Мы покупаем исходный код в Chart Control. Мы нашли, где нам нужно внести некоторые изменения в этот источник контроля и скомпилировать нашу собственную версию. Теперь, чтобы убедиться, что мы ничего не сломали, мне нужно написать несколько модульных тестов, которым нужен доступ к некоторым внутренним полям.

Это идеальный случай, когда InternalsVisible имеет смысл.

Мне было интересно, однако, что вы делаете, если у вас нет доступа к источнику? Как вы могли добраться до внутреннего поля? .Net Reflector может видеть этот код, но я думаю, он просто смотрит на IL.

...