Tutoriel : Tester une tâche personnalisée
Vous pouvez utiliser la fonctionnalité de test unitaire dans Visual Studio pour tester une tâche personnalisée MSBuild avant la distribution afin de garantir l’exactitude du code. Pour plus d’informations sur les avantages des tests et des outils de test de base, consultez Principes de base sur les tests unitaires. Dans ce tutoriel, vous utilisez les exemples de code utilisés dans d’autres tutoriels de tâches personnalisées MSBuild. Les projets suivants utilisés dans ces tutoriels sont disponibles dans GitHub et incluent des tests unitaires et d’intégration pour les tâches personnalisées MSBuild :
Test unitaire
Une tâche personnalisée MSBuild est une classe qui hérite de Task (directement ou indirectement, car ToolTask hérite de Task). La méthode qui effectue les actions associées à la tâche est Execute()
. Cette méthode prend certaines valeurs d’entrée (paramètres) et possède des paramètres de sortie que vous pouvez utiliser pour tester la validité. Dans ce cas, certains paramètres d’entrée étant des chemins d’accès aux fichiers, cet exemple contient des fichiers d’entrée de test dans un dossier appelé Resources. Cette tâche MSBuild génère également des fichiers, de sorte que le test affirme les fichiers générés.
Un moteur de build est nécessaire ; il s’agit d’une classe qui implémente IBuildEngine. Dans cet exemple, vous avez un objet fictif qui utilise Moq, mais vous pouvez utiliser d’autres outils fictifs. L’exemple collecte les erreurs, mais vous pouvez collecter d’autres informations, puis les affirmer.
La simulation Engine
est nécessaire sur tous les tests ; elle est donc incluse comme TestInitialize
(elle est exécutée avant chaque test, et chaque test a son propre moteur de génération).
Pour obtenir le code complet, consultez AppSettingStronglyTypedTest.cs dans le référentiel d’exemples .NET sur GitHub.
Créez la tâche et définissez les paramètres dans le cadre de l’arrangement de test :
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)); }
Créez l’objet fictif de paramètre ITaskItem (à l’aide de Moq) et pointez sur le fichier à analyser. Ensuite, créez la tâche personnalisée
AppSettingStronglyTyped
avec ses paramètres. Enfin, définissez le moteur de build sur la tâche personnalisée 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;
Ensuite, exécutez le code de tâche pour effectuer l’action de tâche réelle :
//Act var success = appSettingStronglyTyped.Execute();
Enfin, affirmez le résultat attendu du test :
//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
Les autres tests suivent ce modèle et étendent toutes les possibilités.
Notes
Quand des fichiers sont générés, vous devez utiliser un nom de fichier différent pour chaque test afin d’éviter toute collision. N’oubliez pas de supprimer les fichiers générés en tant que nettoyage de test.
Tests d’intégration
Les tests unitaires sont importants, mais vous devez également tester la tâche MSBuild personnalisée dans un contexte de build réaliste.
La classe System.Diagnostics.Process fournit l’accès à des processus locaux ainsi que distants, et vous permet de démarrer et d’arrêter des processus système locaux. Cet exemple exécute une build sur un test unitaire à l’aide de fichiers MSBuild de test.
Le code de test doit initialiser le contexte d’exécution pour chaque test. Veillez à ce que le chemin d’accès à la commande
dotnet
soit exact pour votre environnement. L’exemple complet se trouve ici.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; }
Lors du nettoyage, le test doit terminer le processus :
[TestCleanup()] public void Cleanup() { buildProcess.Close(); }
Maintenant, créez chaque test. Chaque test a besoin de sa propre définition de fichier MSBuild pour être exécuté. Par exemple testscript-success.msbuild. Pour comprendre le fichier, consultez Tutoriel : Créer une tâche personnalisée.
<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>
L’argument de test donne les instructions pour générer ce fichier MSBuild :
//Arrange buildProcess.StartInfo.Arguments = "build .\\Resources\\testscript-success.msbuild /t:generateSettingClass";
Exécutez et obtenez la sortie :
//Act ExecuteCommandAndCollectResults();
Où
ExecuteCommandAndCollectResults()
est défini comme :private void ExecuteCommandAndCollectResults() { buildProcess.Start(); while (!buildProcess.StandardOutput.EndOfStream) { output.Add(buildProcess.StandardOutput.ReadLine() ?? string.Empty); } buildProcess.WaitForExit(); }
Enfin, évaluez le résultat attendu :
//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
Conclusion
Les tests unitaires sont utiles, car vous pouvez tester et déboguer le code pour garantir l’exactitude de chaque élément de code spécifique, mais il est important d’avoir des tests d’intégration pour vous assurer que la tâche s’exécute dans un contexte de génération réaliste. Dans ce tutoriel, vous avez appris à tester une tâche personnalisée MSBuild.
Étapes suivantes
Créez une tâche personnalisée plus complexe qui génère du code d’API REST.