Формирование и компиляция кода, а также соглашения об именовании в Microsoft Fakes
В этой статье рассматриваются проблемы и параметры, связанные с созданием и компиляцией кода Fakes, а также описаны соглашения об именовании для типов, элементов и параметров, создаваемых в Fakes.
Требования
Visual Studio Enterprise
Проект .NET Framework
Поддержка проектов в стиле пакета SDK, .NET Core и .NET 5.0, представленная в Visual Studio 2019 (обновление 6), включена по умолчанию в обновлении 8. Дополнительные сведения см. в статье Microsoft Fakes для проектов .NET Core и проектов в стиле SDK.
Создание и компиляция кода
Настройка формирования кода заглушек
Создание типов заглушек настраивается в XML-файле с расширением FAKES. Платформа Fakes интегрируется в процесс сборки с помощью пользовательских задач MSBuild и обнаруживает эти файлы во время сборки. Генератор кода Fakes компилирует типы заглушек в сборку и добавляет ссылку на проект.
Следующий пример иллюстрирует типы заглушек, определенные в FileSystem.dll:
<Fakes xmlns="http://schemas.microsoft.com/fakes/2011/">
<Assembly Name="FileSystem"/>
</Fakes>
Фильтрация типов
Фильтры можно задать в файле FAKES, чтобы ограничить перечень типов, которые должны быть заменены заглушками. Можно добавить неограниченное число элементов Clear, Add, Remove в элемент StubGeneration, чтобы сформировать список выбранных типов.
Например, следующий файл FAKES создает заглушки для типов в пространствах имен System и System.IO, но исключает любой тип, содержащий Handle в пространстве имен System:
<Fakes xmlns="http://schemas.microsoft.com/fakes/2011/">
<Assembly Name="mscorlib" />
<!-- user code -->
<StubGeneration>
<Clear />
<Add Namespace="System!" />
<Add Namespace="System.IO!"/>
<Remove TypeName="Handle" />
</StubGeneration>
<!-- /user code -->
</Fakes>
В строках фильтра используется простая грамматика для определения того, как именно следует выполнять сопоставление:
По умолчанию фильтры не учитывают регистр, выполняется сравнение подстрок:
el
соответствует значению helloДобавление
!
в конец фильтра обеспечивает точное совпадение с учетом регистра:el!
не соответствует значению hellohello!
соответствует значению helloДобавление
*
в конец фильтра обеспечивает соответствие префиксу строки:el*
не соответствует значению hellohe*
соответствует значению helloНесколько фильтров в списке, разделенных точкой с запятой, объединяются в виде дизъюнкции:
el;wo
соответствует значениям hello и world
Создание заглушек для конкретных классов и виртуальных методов
По умолчанию типы заглушек создаются для всех незапечатанных классов. Типы заглушки можно ограничить абстрактными классами с помощью файла конфигурации FAKES:
<Fakes xmlns="http://schemas.microsoft.com/fakes/2011/">
<Assembly Name="mscorlib" />
<!-- user code -->
<StubGeneration>
<Types>
<Clear />
<Add AbstractClasses="true"/>
</Types>
</StubGeneration>
<!-- /user code -->
</Fakes>
Внутренние типы
Генератор кода Fakes создает типы оболочек и типы-заглушки для типов, которые являются видимыми для созданной сборки Fakes. Чтобы сделать внутренние типы сборки с оболочкой совместимости видимыми для сборки Fakes и тестовой сборки, добавьте атрибуты InternalsVisibleToAttribute в код сборки с оболочкой совместимости, отвечающий за видимость для созданной сборки Fakes и тестовой сборки. Приведем пример:
// FileSystem\AssemblyInfo.cs
[assembly: InternalsVisibleTo("FileSystem.Fakes")]
[assembly: InternalsVisibleTo("FileSystem.Tests")]
Внутренние типы в сборках со строгими именами
Если сборка с оболочкой совместимости имеет строгое имя и требуется доступ к внутренним типам сборки:
Как тестовая сборка, так и сборка Fakes должна иметь строгое имя.
Добавьте открытые ключи сборки Fakes и тестовой сборки в атрибуты InternalsVisibleToAttribute в сборках с оболочкой совместимости. Вот как будут выглядеть образцы атрибутов в коде сборки с оболочкой совместимости, когда сборка с оболочкой совместимости имеет строгое имя:
// FileSystem\AssemblyInfo.cs [assembly: InternalsVisibleTo("FileSystem.Fakes", PublicKey=<Fakes_assembly_public_key>)] [assembly: InternalsVisibleTo("FileSystem.Tests", PublicKey=<Test_assembly_public_key>)]
Если сборка с оболочкой совместимости имеет строгое имя, платформа Fakes автоматически назначает созданной сборке Fakes строгую подпись. Тестовой сборке следует назначить строгую подпись. См. раздел Сборки со строгими именами.
Платформа Fakes использует один и тот же ключ для подписывания всех созданных сборок, поэтому этот фрагмент кода можно использовать в качестве основы для добавления атрибута InternalsVisibleTo для сборки Fakes в код сборки с оболочкой совместимости.
[assembly: InternalsVisibleTo("FileSystem.Fakes, PublicKey=0024000004800000940000000602000000240000525341310004000001000100e92decb949446f688ab9f6973436c535bf50acd1fd580495aae3f875aa4e4f663ca77908c63b7f0996977cb98fcfdb35e05aa2c842002703cad835473caac5ef14107e3a7fae01120a96558785f48319f66daabc862872b2c53f5ac11fa335c0165e202b4c011334c7bc8f4c4e570cf255190f4e3e2cbc9137ca57cb687947bc")]
Можно указать другой открытый ключ для сборки Fakes, например ключ, созданный для сборки с оболочкой совместимости, указав полный путь к SNK-файлу, который содержит альтернативный ключ в виде значения атрибута KeyFile
в элементе Fakes
\Compilation
FAKES-файла. Например:
<-- FileSystem.Fakes.fakes -->
<Fakes ...>
<Compilation KeyFile="full_path_to_the_alternate_snk_file" />
</Fakes>
Затем следует использовать открытый ключ из альтернативного SNK-файла в качестве второго параметра атрибута InternalVisibleTo для сборки Fakes в коде сборки с оболочкой совместимости:
// FileSystem\AssemblyInfo.cs
[assembly: InternalsVisibleTo("FileSystem.Fakes",
PublicKey=<Alternate_public_key>)]
[assembly: InternalsVisibleTo("FileSystem.Tests",
PublicKey=<Test_assembly_public_key>)]
В приведенном выше примере значения Alternate_public_key
и Test_assembly_public_key
могут быть одинаковыми.
Оптимизация времени сборки
Компиляция сборок Fakes может значительно затянуть время сборки. Можно сократить время сборки, создав сборки имитаций для сборки Fakes для системных сборок платформы .NET системы и сторонних сборок в отдельном централизованном проекте. Поскольку такие сборки редко изменяются на компьютере, созданные сборки Fakes можно повторно использовать в других проектах.
Из проектов модульных тестов добавьте ссылку на скомпилированные сборки Fakes, помещенные в FakesAssemblies в папке проекта.
Создайте новую библиотеку классов с версией среды выполнения .NET, соответствующей тестовым проектам. Назовем ее Fakes.Prebuild. Удалите файл class1.cs в проекте, так как он нам не нужен.
Добавьте ссылку на все системные и сторонние сборки, для которых требуется Fakes.
Добавьте файл FAKES для каждой сборки и выполните сборку.
В тестовом проекте
Убедитесь в наличии ссылки на библиотеку DLL среды выполнения Fakes:
%ProgramFiles(x86)%\Microsoft Visual Studio\2017\Enterprise\Common7\IDE\PublicAssemblies\Microsoft.QualityTools.Testing.Fakes.dll
Для каждой сборки, для которой вы создали Fakes, добавьте ссылку на соответствующий файл DLL в папке Fakes.Prebuild\FakesAssemblies проекта.
Предотвращение конфликтов имен сборок
В среде Team Build все выходные данные сборки объединяются в одном каталоге. Если Fakes используется в нескольких проектах, может возникнуть ситуация, когда сборки Fakes из разных версий переопределяют друг друга. Например, как сборки Fakes TestProject1 mscorlib.dll из .NET Framework 2.0, так и сборки Fakes TestProject2 mscorlib.dll для .NET Framework 4 будут выводить данные в сборку mscorlib.Fakes.dll.
Чтобы избежать этой проблемы, платформа Fakes должна автоматически создавать учитывающие версию имена сборок Fakes для ссылок, не относящихся к проектам, при добавлении файлов FAKES. Учитывающее версию имя сборки Fakes внедряет номер версии при создании имени сборки Fakes:
В случае со сборкой Fakes MyAssembly и версией 1.2.3.4 имя будет иметь вид MyAssembly.1.2.3.4.Fakes.
Можно изменить или удалить эту версию, изменив атрибут Version элемента Assembly в файле FAKES:
attribute of the Assembly element in the .fakes:
<Fakes ...>
<Assembly Name="MyAssembly" Version="1.2.3.4" />
...
</Fakes>
Соглашения об именовании для Fakes
Соглашения об именовании для типов заглушек и типов оболочек
Пространства имен
К пространству имен добавляется суффикс .Fakes.
Например,
System.Fakes
пространство имен содержит типы оболочек пространства имен System.Global.Fakes содержит тип оболочки пустого пространства имен.
Имена типов
Префикс оболочки добавляется к имени типа для получения имени типа оболочки.
Например, ShimExample является типом оболочки типа Example.
Префикс заглушки добавляется к имени типа для получения имени типа заглушки.
Например, StubIExample является типом заглушки типа IExample.
Аргументы типа и структуры вложенных типов
Аргументы универсального типа копируются.
Структура вложенного типа копируется для типов оболочек.
Соглашения об именовании для свойства делегата оболочки или поля делегата заглушки
Основные правила для именования полей, начиная с пустого имени:
Имя метода добавляется.
Если имя метода является явной реализацией интерфейса, точки удаляются.
Если метод является универсальным, добавляется
Of
n, где n — число аргументов универсального метода.Имена особых методов, таких как методы получения или задания свойства, обрабатываются согласно правилам в приведенной ниже таблице.
Чем является метод... | Пример | Добавление к имени метода |
---|---|---|
Конструктор | .ctor |
Constructor |
Статический конструктор | .cctor |
StaticConstructor |
Метод доступа, имя которого состоит из двух частей, разделенных символом "_" (например, методы получения свойств) | kind_name (распространенный вариант, однако он не является обязательным согласно ECMA) | NameKind, где обе части начинаются с прописных букв и поменяны местами |
Метод получения свойства Prop |
PropGet |
|
Метод задания свойства Prop |
PropSet |
|
Метод добавления события | Add |
|
Метод удаления события | Remove |
|
Оператор, состоящий из двух частей | op_name |
NameOp |
Например, оператор + | op_Add |
AddOp |
Для оператора преобразования добавляется тип возвращаемого значения. | T op_Implicit |
ImplicitOpT |
Примечание.
- Методы получения и задания индексаторов обрабатываются так же, как и методы для свойств. Для индексаторов имя по умолчанию имеет значение
Item
. - Имена типов параметров преобразуются и объединяются.
- Тип возвращаемого значения игнорируется, если нет неоднозначности перегрузки. При наличии неоднозначности перегрузки тип возвращаемого значения добавляется в конец имени.
Соглашения об именовании для типов параметров
Выдано | Добавляемая строка... |
---|---|
ТипT |
T Пространство имен, вложенная структура и универсальные регистрации удаляются. |
Параметр выводаout T |
TOut |
Параметр ссылки ref T |
TRef |
Тип массиваT[] |
TArray |
Тип многомерного массиваT[ , , ] |
T3 |
Тип указателяT* |
TPtr |
Универсальный типT<R1, ...> |
TOfR1 |
Аргумент универсального типа!i для типа C<TType> |
Ti |
Аргумент универсального метода!!i для метода M<MMethod> |
Mi |
Вложенный типN.T |
Добавляется N , затем T |
Рекурсивные правила
Рекурсивно применяются следующие правила:
Поскольку платформа Fakes использует C# для создания сборок Fakes, любой символ приведет к тому, что недопустимый токен C#, экранируется за «_» (символ подчеркивания).
Если результирующее имя конфликтует с любым членом объявляющего типа, используется схема нумерации, заключающаяся в добавлении двухзначного счетчика, начиная со значения 01.
Использование Microsoft Fakes в непрерывной интеграции
Создание сборки Microsoft Fakes
Microsoft Fakes — это функция, доступная исключительно в Visual Studio Enterprise. Таким образом, создание сборок Fakes требует использования задачи сборки Visual Studio при создании проекта.
Примечание.
Альтернативная стратегия заключается в проверке сборок Fakes непосредственно в системе непрерывной интеграции (CI) и использовании задачи MSBuild. Если вы выбрали этот подход, необходимо включить ссылку на сборку созданной сборки Fakes в тестовом проекте, как показано в следующем фрагменте кода:
<Project Sdk="Microsoft.NET.Sdk">
<ItemGroup>
<Reference Include="FakesAssemblies\System.Fakes.dll"/>
</ItemGroup>
</Project>
Эта ссылка должна быть добавлена вручную, специально для проектов в стиле SDK (т. е. .NET Core, .NET 5+ и платформа .NET Framework), так как эти проекты теперь неявно добавляют ссылки на сборки. Если вы решите использовать этот метод, обязательно обновите сборку Fakes всякий раз, когда родительская сборка проходит изменения.