Учебник. Проверка настраиваемой задачи
Вы можете использовать функциональные возможности модульного тестирования в Visual Studio, чтобы проверить настраиваемую задачу MSBuild перед выпуском и обеспечить правильность кода. Сведения о преимуществах выполнения тестов и основных средствах для проверки см. в статье Основные сведения о модульных тестах. Этот учебник включает примеры кода, которые используются в других учебниках по настраиваемым задачам MSBuild. Следующие проекты, используемые в этих учебниках, доступны в GitHub и включают модульные и интеграционные тесты для настраиваемых задач MSBuild:
Модульный тест
Настраиваемая задача MSBuild — это класс, который наследуется от Task (прямо или косвенно, потому что ToolTask наследует от Task). Метод, выполняющий действия, связанные с задачей, — Execute()
. Этот метод принимает некоторые входные значения (параметры) и имеет выходные параметры, которые можно использовать для проверочного утверждения, чтобы проверить допустимость. В этом случае некоторые входные параметры являются путями к файлам, поэтому в этом примере входные файлы для теста находятся в папке с именем Resources. Эта задача MSBuild также создает файлы, поэтому тест выполняет проверяет созданные файлы.
Требуется подсистема сборки, которая является классом, реализующим IBuildEngine. В этом примере есть макет, который использует Moq, но можно использовать и другие средства макетирования. В примере собираются ошибки, но можно собрать другие сведения и затем проверить их.
Макет Engine
необходим для всех тестов, поэтому он включается как TestInitialize
(выполняется перед каждым тестом, и в каждом тесте есть собственная подсистема сборки).
Полный код см. в разделе AppSettingStronglyTypedTest.cs в репозитории примеров .NET на GitHub.
Создайте задачу и задайте параметры в составе тестовой конфигурации:
private Mock<IBuildEngine> buildEngine; private List<BuildErrorEventArgs> errors; [TestInitialize()] public void Startup() { buildEngine = new Mock<IBuildEngine>(); errors = new List<BuildErrorEventArgs>(); buildEngine.Setup(x => x.LogErrorEvent(It.IsAny<BuildErrorEventArgs>())).Callback<BuildErrorEventArgs>(e => errors.Add(e)); }
Создайте макет параметров ITaskItem (с помощью Moq) и наведите указатель на файл, который необходимо проанализировать. Затем создайте пользовательскую задачу
AppSettingStronglyTyped
с ее параметрами. Наконец, задайте для подсистемы сборки MSBuild настраиваемую задачу://Arrange var item = new Mock<ITaskItem>(); item.Setup(x => x.GetMetadata("Identity")).Returns($".\\Resources\\complete-prop.setting"); var appSettingStronglyTyped = new AppSettingStronglyTyped { SettingClassName = "MyCompletePropSetting", SettingNamespaceName = "MyNamespace", SettingFiles = new[] { item.Object } }; appSettingStronglyTyped.BuildEngine = buildEngine.Object;
Затем исполните код задачи, чтобы выполнить фактическое действие задачи:
//Act var success = appSettingStronglyTyped.Execute();
Наконец, выполните проверочное утверждение ожидаемого результата теста:
//Assert Assert.IsTrue(success); // The execution was success Assert.AreEqual(errors.Count, 0); //Not error were found Assert.AreEqual($"MyCompletePropSetting.generated.cs", appSettingStronglyTyped.ClassNameFile); // The Task expected output Assert.AreEqual(true, File.Exists(appSettingStronglyTyped.ClassNameFile)); // The file was generated Assert.IsTrue(File.ReadLines(appSettingStronglyTyped.ClassNameFile).SequenceEqual(File.ReadLines(".\\Resources\\complete-prop-class.txt"))); // Assenting the file content
Другие тесты следуют этому шаблону.
Примечание.
При создании файлов необходимо использовать разные имена файлов для каждого теста, чтобы избежать конфликтов. Не забудьте удалить созданные файлы в ходе очистки теста.
Интеграционные тесты
Модульные тесты важны, но настраиваемую задачу MSBuild также необходимо протестировать в реалистичном контексте сборки.
Класс System.Diagnostics.Process предоставляет доступ к локальным и удаленным процессам и позволяет запускать и останавливать локальные системные процессы. В этом примере выполняется сборка для модульного теста с помощью файлов теста MSBuild.
Код теста должен инициализировать контекст выполнения для каждого теста. Обязательно проверьте точность пути к команде
dotnet
для вашей среды. Полный пример приведен здесь.public const string MSBUILD = "C:\\Program Files\\dotnet\\dotnet.exe"; private Process buildProcess; private List<string> output; [TestInitialize()] public void Startup() { output = new List<string>(); buildProcess = new Process(); buildProcess.StartInfo.FileName = MSBUILD; buildProcess.StartInfo.WindowStyle = ProcessWindowStyle.Hidden; buildProcess.StartInfo.CreateNoWindow = true; buildProcess.StartInfo.RedirectStandardOutput = true; }
При очистке тест должен завершить процесс:
[TestCleanup()] public void Cleanup() { buildProcess.Close(); }
Теперь создайте каждый тест. Для каждого теста потребуется выполнить собственное определение файла MSBuild. Например testscript-success.msbuild. Сведения о файле см. в статье Учебник. Создание настраиваемого задания.
<Project Sdk="Microsoft.NET.Sdk"> <UsingTask TaskName="AppSettingStronglyTyped.AppSettingStronglyTyped" AssemblyFile="..\AppSettingStronglyTyped.dll" /> <PropertyGroup> <TargetFramework>netstandard2.1</TargetFramework> </PropertyGroup> <PropertyGroup> <SettingClass>MySettingSuccess</SettingClass> <SettingNamespace>example</SettingNamespace> </PropertyGroup> <ItemGroup> <SettingFiles Include="complete-prop.setting" /> </ItemGroup> <Target Name="generateSettingClass"> <AppSettingStronglyTyped SettingClassName="$(SettingClass)" SettingNamespaceName="$(SettingNamespace)" SettingFiles="@(SettingFiles)"> <Output TaskParameter="ClassNameFile" PropertyName="SettingClassFileName" /> </AppSettingStronglyTyped> </Target> </Project>
Аргумент теста содержит инструкции по сборке этого файла MSBuild:
//Arrange buildProcess.StartInfo.Arguments = "build .\\Resources\\testscript-success.msbuild /t:generateSettingClass";
Выполните и получите выходные данные:
//Act ExecuteCommandAndCollectResults();
ExecuteCommandAndCollectResults()
определяется как:private void ExecuteCommandAndCollectResults() { buildProcess.Start(); while (!buildProcess.StandardOutput.EndOfStream) { output.Add(buildProcess.StandardOutput.ReadLine() ?? string.Empty); } buildProcess.WaitForExit(); }
Наконец, оцените ожидаемый результат:
//Assert Assert.AreEqual(0, buildProcess.ExitCode); //Finished success Assert.IsTrue(File.Exists(".\\Resources\\MySettingSuccess.generated.cs")); // the expected resource was generated Assert.IsTrue(File.ReadLines(".\\Resources\\MySettingSuccess.generated.cs").SequenceEqual(File.ReadLines(".\\Resources\\testscript-success-class.txt"))); // asserting the file content
Заключение
Модульное тестирование полезно, так как вы можете проверять и отлаживать код, чтобы гарантировать правильность каждого отдельного фрагмента кода, но проведение интеграционных тестов важно для того, чтобы убедиться, что задача будет выполнена в реалистичном контексте сборки. В этом учебнике вы узнали, как проверить настраиваемую задачу MSBuild.
Следующие шаги
Создайте более сложную настраиваемую задачу, которая выполняет создание кода с помощью REST API.
Обратная связь
https://aka.ms/ContentUserFeedback.
Ожидается в ближайшее время: в течение 2024 года мы постепенно откажемся от GitHub Issues как механизма обратной связи для контента и заменим его новой системой обратной связи. Дополнительные сведения см. в разделеОтправить и просмотреть отзыв по