Модульное тестирование внутренних методов в библиотеке VS2017 .Net Standard

150

В настоящее время я работаю с последней версией кандидата на выпуск Visual Studio 2017, создавая библиотеку .Net Standard 1.6. Я использую xUnit для модульного тестирования моего кода, и мне было интересно, можете ли вы по-прежнему тестировать внутренние методы в VS2017.

Я помню, что вы могли бы все строки класса AssemblyInfo.cs в VS2015, которые позволили бы указанным проектам видеть внутренние методы

[assembly:InternalsVisibleTo("MyTests")]

Поскольку в проектах VS2017 .Net Standard нет класса AssemblyInfo.cs, мне было интересно, можно ли по-прежнему использовать внутренние методы для модульного тестирования?

Фил Мюррей
источник
3
Вы должны быть в состоянии выполнить модульное тестирование своего кода только с внешне видимой функциональностью. В конце концов, если никакой логический путь из внешнего кода не может достичь этих внутренних методов, то что они будут делать там в первую очередь?
Дэвид
3
@ Давид Я могу и сделал это, но раньше я проводил простые модульные тесты для некоторых внутренних классов. Просто чтобы быть более явным в тестировании.
Фил Мюррей
5
AFAIK, вы можете поместить этот атрибут в любой другой файл, вне namespaceблока, и он должен скомпилироваться. В этом не должно быть ничего волшебного AssemblyInfo.cs. Разве это не работает? Конечно, вам нужно добавить правильное usingпредложение или использовать полностью определенный атрибут [assembly: System.Runtime.CompilerServices.InternalsVisibleTo("Something")].
Гру
1
@David Если вы создаете библиотеку с внутренними классами, и вам необходимо протестировать и смоделировать эти классы, InternalsVisibleToочень важно - например, здесь - stackoverflow.com/a/17574183/43453
PandaWood

Ответы:

210

Согласно документам .NET дляInternalsVisibleToAttribute :

Атрибут применяется на уровне сборки. Это означает, что его можно включить в начало файла исходного кода или в файл AssemblyInfo в проекте Visual Studio.

Другими словами, вы можете просто поместить его в свой произвольно названный файл .cs, и он должен работать нормально:

// some .cs file included in your project
using System.Runtime.CompilerServices;
[assembly:InternalsVisibleTo("MyTests")]
Гру
источник
1
@PhilMurray: также, кажется, есть настройка, которая должна позволить вам создать «классический» AssemblyInfo.csфайл, как описано здесь . В противном случае все атрибуты, такие как «description», «copyright» и другие, хранятся в файле .csproj.
Гру
43

Как описано здесь:

https://blog.sanderaernouts.com/make-internals-visible-with-new-csproj-format

Можно добавить внутренний видимый атрибут в файл проекта, добавив еще одну ItemGroup:

<ItemGroup>
    <AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleTo">
        <_Parameter1>$(AssemblyName).Tests</_Parameter1>
    </AssemblyAttribute>
</ItemGroup>

или даже:

<ItemGroup>
    <AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleTo">
        <_Parameter1>$(MSBuildProjectName).Tests</_Parameter1>
    </AssemblyAttribute>
</ItemGroup>

Мне нравится это решение, потому что файл проекта, кажется, является правильным местом для определения таких проблем.

JanDotNet
источник
8

Пока с первым ответом все отлично. Если вы чувствуете, что все еще хотите сделать это в оригинале, AssemblyInfoвы всегда можете не создавать файл автоматически и добавлять его вручную.

<PropertyGroup>
   <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
</PropertyGroup>

Для получения дополнительной информации: https://stackoverflow.com/a/47075759/869033

Ник Н.
источник
5

Атрибут «InternalsVisibleTo» является ключом к любому виду «белого ящика» (я полагаю, термин десятилетия) для тестирования .Net. Его можно поместить в любой файл C # с атрибутом «Assembly» на передней панели. Обратите внимание, что MS DOC говорят, что имя сборки должно быть квалифицировано токеном открытого ключа, если он подписан. Иногда это не работает, и нужно использовать полный открытый ключ вместо него. Доступ к внутренним компонентам является ключом к тестированию параллельных систем и во многих других ситуациях. См. Https://www.amazon.com/xUnit-Test-Patterns-Refactoring-Code/dp/0131495054 . В этой книге Месарош описывает множество стилей кодирования, которые в основном составляют подход «Дизайн для теста» к разработке программ. По крайней мере, так я и использовал на протяжении многих лет.

ДОБАВЛЕНО: Извините, я не был здесь некоторое время. Один из подходов Месарош назвал «подходом подкласса тестирования». Опять же, нужно использовать «internalsvisableto» для доступа к внутренним компонентам базового класса. Это отличное решение, но оно не работает для закрытых классов. Когда я преподаю «Дизайн для тестирования», я предполагаю, что это одна из вещей, которые необходимо «предварительно спроектировать» в базовые классы, чтобы обеспечить тестируемость. Это должно стать почти культурной вещью. Создайте «базовый» базовый класс, который будет закрыт. Назовите это UnsealedBaseClass или что-то однообразно узнаваемое. Это класс, который нужно разделить на подклассы для тестирования. Это также подкласс для создания производственного герметичного класса, который часто отличается только конструкторами, которые он выставляет. Я работаю в атомной отрасли, и требования к испытаниям принимаются ОЧЕНЬ серьезно. Итак, я должен думать об этом все время. Кстати, оставить тестирование в производственном коде не является проблемой в нашей области, поскольку они являются «внутренними» в реализации .Net. Последствия НЕ тестирования чего-либо могут быть довольно глубокими.

kurt.matis
источник
1

Другой способ - использовать открытый класс TestMyFoo «обертки» внутри целевого проекта, который имеет открытые методы и наследует от класса, который нужно протестировать (например, MyFoo). Эти открытые методы просто обращаются к базовому классу, который вы хотите протестировать.

Это не «идеально», так как в конечном итоге вы отправляете тестовый хук в свой целевой проект. Но рассмотрим современные надежные автомобили с диагностическими портами и современную надежную электронику с разъемом JTAG. Но никто не настолько глуп, чтобы водить машину, используя диагностический порт.

Эндрю Пэйт
источник