Samouczek: testowanie zadania niestandardowego
Możesz użyć funkcji testowania jednostkowego w programie Visual Studio, aby przetestować niestandardowe zadanie MSBuild przed dystrybucją, aby zapewnić poprawność kodu. Aby uzyskać informacje o zaletach wykonywania testów i podstawowych narzędzi testowych, zobacz podstawowe informacje na temat testów jednostkowych. W tym samouczku użyto przykładów kodu używanych w innych samouczkach zadań niestandardowych programu MSBuild. Następujące projekty używane w tych samouczkach są dostępne w usłudze GitHub i obejmują testy jednostkowe i integracyjne dla zadań niestandardowych programu MSBuild:
Test jednostkowy
Zadanie niestandardowe programu MSBuild to klasa dziedziczona bezpośrednio Task lub pośrednio, ponieważ ToolTask dziedziczy z Taskklasy ). Metoda wykonująca akcje skojarzone z zadaniem to Execute()
. Ta metoda przyjmuje niektóre wartości wejściowe (parametry) i ma parametry wyjściowe, których można użyć do testowania poprawności. W tym przypadku niektóre parametry wejściowe są ścieżkami do plików, więc w tym przykładzie znajdują się pliki wejściowe testowe w folderze o nazwie Resources. To zadanie MSBuild generuje również pliki, więc test potwierdza wygenerowane pliki.
Wymagany jest aparat kompilacji, który jest klasą implementjącą IBuildEngine. W tym przykładzie istnieje pozorowanie przy użyciu narzędzia Moq, ale można użyć innych pozornych narzędzi. Przykład zbiera błędy, ale możesz zebrać inne informacje, a następnie je potwierdzić.
Pozorowanie Engine
jest wymagane we wszystkich testach, więc jest uwzględniane jako TestInitialize
(jest wykonywane przed każdym testem, a każdy test ma własny aparat kompilacji).
Pełny kod można znaleźć w pliku AppSettingStronglyTypedTest.cs w repozytorium przykładów platformy .NET w witrynie GitHub.
Utwórz zadanie i ustaw parametry w ramach układu testu:
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)); }
Utwórz pozorny ITaskItem parametr (przy użyciu narzędzia Moq) i wskaż plik, który ma zostać przeanalizowany. Następnie utwórz
AppSettingStronglyTyped
zadanie niestandardowe z jego parametrami. Na koniec ustaw aparat kompilacji na zadanie niestandardowe 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;
Następnie wykonaj kod zadania, aby wykonać rzeczywistą akcję zadania:
//Act var success = appSettingStronglyTyped.Execute();
Na koniec należy potwierdzić oczekiwany wynik testu:
//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
Pozostałe testy są zgodne z tym wzorcem i rozszerzają wszystkie możliwości.
Uwaga
W przypadku wygenerowania plików należy użyć innej nazwy pliku dla każdego testu, aby uniknąć kolizji. Pamiętaj, aby usunąć wygenerowane pliki jako oczyszczanie testów.
Testy integracji
Testy jednostkowe są ważne, ale należy również przetestować niestandardowe zadanie MSBuild w realistycznym kontekście kompilacji.
Klasa System.Diagnostics.Process zapewnia dostęp do procesów lokalnych i zdalnych oraz umożliwia uruchamianie i zatrzymywanie lokalnych procesów systemowych. W tym przykładzie jest uruchamiana kompilacja w teście jednostkowym przy użyciu testowych plików MSBuild.
Kod testowy musi zainicjować kontekst wykonywania dla każdego testu. Zwróć uwagę, aby upewnić się, że ścieżka do
dotnet
polecenia jest dokładna dla danego środowiska. Kompletny przykład znajduje się tutaj.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; }
Po oczyszczeniu test musi zakończyć proces:
[TestCleanup()] public void Cleanup() { buildProcess.Close(); }
Teraz utwórz każdy test. Do wykonania każdego testu będzie potrzebna własna definicja pliku MSBuild. Na przykład testscript-success.msbuild. Aby zrozumieć ten plik, zobacz Samouczek: Kreta niestandardowe zadanie.
<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>
Argument testowy zawiera instrukcje dotyczące kompilowania tego pliku MSBuild:
//Arrange buildProcess.StartInfo.Arguments = "build .\\Resources\\testscript-success.msbuild /t:generateSettingClass";
Wykonaj i pobierz dane wyjściowe:
//Act ExecuteCommandAndCollectResults();
Gdzie
ExecuteCommandAndCollectResults()
jest definiowany jako:private void ExecuteCommandAndCollectResults() { buildProcess.Start(); while (!buildProcess.StandardOutput.EndOfStream) { output.Add(buildProcess.StandardOutput.ReadLine() ?? string.Empty); } buildProcess.WaitForExit(); }
Na koniec oceń oczekiwany wynik:
//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
Podsumowanie
Testowanie jednostkowe jest przydatne, ponieważ można testować i debugować kod w celu zapewnienia poprawności każdego konkretnego fragmentu kodu, ale posiadanie testów integracji jest ważne, aby upewnić się, że zadanie jest wykonywane w realistycznym kontekście kompilacji. W tym samouczku przedstawiono sposób testowania niestandardowego zadania MSBuild.
Następne kroki
Utwórz bardziej złożone zadanie niestandardowe, które wykonuje generowanie kodu interfejsu API REST.