자습서: 사용자 지정 작업 테스트

Visual Studio 단위 테스트 기능을 사용하여 배포 전에 MSBuild 사용자 지정 작업을 테스트하여 코드의 정확성을 확인할 수 있습니다. 테스트 수행 및 기본 테스트 도구의 이점에 관한 정보는 단위 테스트에 관한 기본 사항을 참조하세요. 이 자습서에서는 다른 MSBuild 사용자 지정 작업 자습서에서 사용되는 코드 예제를 사용합니다. 이러한 자습서에 사용된 다음 프로젝트는 GitHub에서 사용할 수 있으며 MSBuild 사용자 지정 작업에 대한 단위 및 통합 테스트를 포함합니다.

단위 테스트

MSBuild 사용자 지정 작업은 Task에서 직간접적으로 상속되는 클래스입니다(ToolTaskTask에서 상속되기 때문). 작업과 연결된 작업을 수행하는 메서드는 Execute()입니다. 이 메서드는 일부 입력 값(매개 변수)을 사용하고 Assert를 사용하여 유효성을 테스트할 수 있는 출력 매개 변수가 있습니다. 이 경우, 일부 입력 매개 변수는 파일 경로이므로 이 예제에서는 Resources라는 폴더에 테스트 입력 파일이 있습니다. 또한 이 MSBuild 작업은 파일을 생성하므로 테스트에서 생성된 파일을 어설션합니다.

IBuildEngine을 구현하는 클래스인 빌드 엔진이 필요합니다. 이 예제에서는 Moq를 사용하는 모의 도구가 있지만 다른 모의 도구를 사용할 수 있습니다. 이 예제에서는 오류를 수집하지만 다른 정보를 수집한 후에 어설션할 수 있습니다.

Engine 모의 도구는 모든 테스트에 필요하므로 TestInitialize로서 포함됩니다(매회 테스트에 앞서 실행되며 각 테스트에는 자체 빌드 엔진이 있습니다).

전체 코드는 GitHub의 .NET 샘플 리포지토리에서 AppSettingStronglyTypedTest.cs를 참조하세요.

  1. 작업을 만들고 테스트 정렬의 일부로 매개 변수를 설정합니다.

        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));
         }
    
  2. Moq를 사용하여 모의 매개 변수인 ITaskItem을 만들고 구문 분석할 파일을 가리킵니다. 그런 다음, 매개 변수를 사용하여 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();
    
  3. 마지막으로 테스트의 예상 결과를 어설션합니다.

    //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
    
  4. 다른 테스트는 이 패턴을 따르고 모든 가능성을 확장합니다.

참고 항목

생성된 파일이 있는 경우, 충돌을 방지하기 위해 각 테스트에 다른 파일 이름을 사용해야 합니다. 생성된 파일을 테스트 정리로 삭제해야 합니다.

통합 테스트

단위 테스트는 중요하지만 실제 빌드 컨텍스트에서 사용자 지정 MSBuild 작업도 테스트해야 합니다.

System.Diagnostics.Process Class는 로컬 및 원격 프로세스에 대한 액세스를 제공하며 로컬 시스템 프로세스를 시작하고 중지할 수 있습니다. 이 예제에서는 테스트 MSBuild 파일을 사용하여 단위 테스트에서 빌드를 실행합니다.

  1. 테스트 코드는 각 테스트에 대한 실행 컨텍스트를 초기화해야 합니다. 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;
         }
    
  2. 정리 시 테스트는 프로세스를 완료해야 합니다.

        [TestCleanup()]
         public void Cleanup()
         {
             buildProcess.Close();
         }
    
  3. 이제 각 테스트를 만듭니다. 각 테스트를 실행하려면 자체 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>
    
  4. 테스트 인수는 이 MSBuild 파일을 빌드하는 지침을 제공합니다.

     //Arrange
     buildProcess.StartInfo.Arguments = "build .\\Resources\\testscript-success.msbuild /t:generateSettingClass";
    
  5. 출력을 실행하고 가져옵니다.

    //Act
    ExecuteCommandAndCollectResults();
    

    ExecuteCommandAndCollectResults()를 다음과 같이 정의한 경우:

    private void ExecuteCommandAndCollectResults()
    {
         buildProcess.Start();
         while (!buildProcess.StandardOutput.EndOfStream)
         {
             output.Add(buildProcess.StandardOutput.ReadLine() ?? string.Empty);
         }
         buildProcess.WaitForExit();
    }
    
  6. 마지막으로, 예상된 결과를 평가합니다.

    //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 코드 생성을 수행하는 더 복잡한 사용자 지정 작업을 만듭니다.