Exercício – Executar o teste de cobertura de código

Concluído

De modo muito semelhante à ferramenta usada para o teste de unidade, a ferramenta usada para cobertura de código depende da linguagem de programação e da estrutura de aplicativo.

Ao direcionar aplicativos .NET para execução no Linux, coverlet é uma opção popular. Coverlet é uma biblioteca de cobertura de código multiplataforma para o .NET.

Como a cobertura de código é feita no .NET?

A maneira de você coletar a cobertura de código depende de qual linguagem de programação e estrutura você está usando e também das ferramentas de cobertura de código disponíveis.

Em nosso cenário de Tailspin, descobrimos que:

  • O Visual Studio no Windows oferece uma maneira de executar a cobertura de código.

  • No entanto, como a estamos desenvolvendo no Linux, podemos usar coverlet, uma biblioteca de cobertura de código multiplataforma para .NET.

    O projeto de teste de unidade exige o pacote do NuGet coverlet.msbuild.

  • Os resultados da cobertura de código são gravados em um arquivo XML para que possam ser processados por outra ferramenta. O Azure Pipelines dá suporte aos formatos de resultados de cobertura do Cobertura e do JaCoCo.

    Nesse módulo, estamos usando a Cobertura.

  • Para converter os resultados de cobertura da Cobertura em um formato legível por humanos, podemos usar uma ferramenta chamada ReportGenerator.

  • ReportGenerator fornece muitos formatos, incluindo HTML. Os formatos HTML criam relatórios detalhados para cada classe em um projeto do .NET.

    Especificamente, há um formato HTML chamado HtmlInline_AzurePipelines que fornece uma aparência visual que corresponde ao Azure Pipelines.

Como posso gerenciar as ferramentas do .NET?

Uma ferramenta do .NET como ReportGenerator é um pacote NuGet especial que contém um aplicativo de console. Você pode gerenciar uma ferramenta do .NET como uma ferramenta global ou uma ferramenta local.

Uma ferramenta global é instalada em um local centralizado e pode ser chamada de qualquer diretório. Uma versão de uma ferramenta global é usada para todos os diretórios no computador.

Uma ferramenta local é uma cópia mais isolada de uma ferramenta .NET que tem como escopo um diretório específico. O escopo permite que diretórios diferentes contenham versões diferentes da mesma ferramenta.

Você usa um arquivo de manifesto para gerenciar as ferramentas locais de um determinado diretório. Esse arquivo está no formato JSON e normalmente é chamado de dotnet-tools.json. Um arquivo de manifesto permite que você descreva as versões específicas da ferramenta de que você precisa para compilar ou executar seu aplicativo.

Quando você inclui o arquivo de manifesto no controle do código-fonte e suas fontes de aplicativo, os desenvolvedores e os sistemas de compilação podem executar o comando dotnet tool restore para instalar todas as ferramentas listadas no arquivo de manifesto. Quando você precisa de uma versão mais recente de uma ferramenta local, basta atualizar a versão no arquivo de manifesto.

Para manter as coisas mais isoladas, você trabalhará com ferramentas locais neste módulo. Você criará um manifesto de ferramenta que inclui a Ferramenta ReportGenerator. Você também modificará seu pipeline de build para instalar a Ferramenta ReportGeneratore converter os resultados da cobertura de código em um formato legível.

Executar cobertura de código localmente

Antes escrever qualquer código de pipeline, você pode experimentar trabalhar manualmente para verificar o processo.

  1. No Visual Studio Code, abra o terminal integrado.

  2. Execute o comando dotnet new a seguir para criar um arquivo de manifesto de ferramenta local.

    dotnet new tool-manifest
    

    O comando cria um arquivo chamado .config/dotnet-tools.json.

  3. Execute o seguinte comando dotnet tool install para instalar o ReportGenerator:

    dotnet tool install dotnet-reportgenerator-globaltool
    

    Esse comando instala a versão mais recente do ReportGenerator e adiciona uma entrada ao arquivo de manifesto da ferramenta.

  4. Execute o seguinte comando dotnet add package para adicionar o pacote coverlet.msbuild ao projeto Tailspin.SpaceGame.Web.Tests:

    dotnet add Tailspin.SpaceGame.Web.Tests package coverlet.msbuild
    
  5. Execute o seguinte comando dotnet test para executar seus testes de unidade e coletar a cobertura de código:

    Observação

    Se você estiver usando o terminal do PowerShell no Visual Studio, o caractere de continuação de linha será um acento grave (`), então use esse caractere no lugar no lugar da barra invertida (\) para comandos em várias linhas.

    dotnet test --no-build \
      --configuration Release \
      /p:CollectCoverage=true \
      /p:CoverletOutputFormat=cobertura \
      /p:CoverletOutput=./TestResults/Coverage/
    

    Se o comando falhar, tente executá-lo da seguinte forma:

    MSYS2_ARG_CONV_EXCL="*" dotnet test --no-build \
      --configuration Release \
      /p:CollectCoverage=true \
      /p:CoverletOutputFormat=cobertura \
      /p:CoverletOutput=./TestResults/Coverage/
    

    Esse comando é semelhante ao que foi executado anteriormente. Os sinalizadores /p: informam o coverlet do formato de cobertura de código a ser usado e em que local colocar os resultados.

  6. Execute o seguinte comando dotnet tool run para usar ReportGenerator para converter o arquivo Cobertura em HTML:

    dotnet tool run reportgenerator \
      -- -reports:./Tailspin.SpaceGame.Web.Tests/TestResults/Coverage/coverage.cobertura.xml \
      -targetdir:./CodeCoverage \
      -reporttypes:HtmlInline_AzurePipelines
    

    Muitos arquivos HTML serão exibidos na pasta CodeCoverage na raiz do projeto.

  7. No Visual Studio Code, expanda a pasta CodeCoverage, clique com o botão direito do mouse em index.htm e selecione Revelar no Explorador de Arquivos (Revelar no Finder no macOS ou Abrir Pasta Recipiente no Linux).

  8. No Windows Explorer (Finder, no macOS), clique duas vezes em index.htm para abri-lo em um navegador da Web.

    Você verá o resumo do relatório de cobertura.

    A screenshot of the local code coverage report summary showing 7.7 percent line coverage.

  9. Role até a parte inferior da página para ver um detalhamento de cobertura por tipo de classe.

    A screenshot of local coverage report class summary showing coverage stats across classes found in the Tailspin.SpaceGame.Web code.

  10. Selecione o link para TailSpin.SpaceGame.Web.LocalDocumentDBRepository<T> para ver mais detalhes.

    Observe o método GetItemsAsync está coberto por testes de unidade, mas o método CountItemsAsync não tem nenhuma cobertura.

    A screenshot of local class coverage detail with a visual representation of unit test coverage for two C# methods, one with all code lines green (covered) and one with all lines red (not covered).

    Isso faz sentido, pois o método de teste FetchOnlyRequestedGameRegion chama o método GetItemsAsync, mas não chama o método CountItemsAsync. (Para examinar o código de teste, veja o arquivo DocumentDBRepository_GetItemsAsyncShould.cs.)

Criar um branch

Agora que você pode compilar um relatório de cobertura de código localmente, está pronto para adicionar tarefas ao seu pipeline de build que executa as mesmas tarefas.

Nesta seção, você criará um branch chamado code-coverage, com base no branch unit-tests, para armazenar seu trabalho. Na prática, você normalmente criaria esse branch com base no branch main.

  1. No Visual Studio Code, abra o terminal integrado.

  2. No terminal, execute o seguinte comando git checkout para criar um branch chamado code-coverage:

    git checkout -B code-coverage
    

Adicionar tarefas de build

Nesta seção, você adicionará tarefas que medem a cobertura de código para o pipeline de build.

  1. No Visual Studio Code, modifique azure-pipelines.yml desta forma:

    trigger:
    - '*'
    
    pool:
      vmImage: 'ubuntu-20.04'
      demands:
      - npm
    
    variables:
      buildConfiguration: 'Release'
      wwwrootDir: 'Tailspin.SpaceGame.Web/wwwroot'
      dotnetSdkVersion: '6.x'
    
    steps:
    - task: UseDotNet@2
      displayName: 'Use .NET SDK $(dotnetSdkVersion)'
      inputs:
        version: '$(dotnetSdkVersion)'
    
    - task: Npm@1
      displayName: 'Run npm install'
      inputs:
        verbose: false
    
    - script: './node_modules/.bin/node-sass $(wwwrootDir) --output $(wwwrootDir)'
      displayName: 'Compile Sass assets'
    
    - task: gulp@1
      displayName: 'Run gulp tasks'
    
    - script: 'echo "$(Build.DefinitionName), $(Build.BuildId), $(Build.BuildNumber)" > buildinfo.txt'
      displayName: 'Write build info'
      workingDirectory: $(wwwrootDir)
    
    - task: DotNetCoreCLI@2
      displayName: 'Restore project dependencies'
      inputs:
        command: 'restore'
        projects: '**/*.csproj'
    
    - task: DotNetCoreCLI@2
      displayName: 'Build the project - $(buildConfiguration)'
      inputs:
        command: 'build'
        arguments: '--no-restore --configuration $(buildConfiguration)'
        projects: '**/*.csproj'
    
    - task: DotNetCoreCLI@2
      displayName: 'Install .NET tools from local manifest'
      inputs:
        command: custom
        custom: tool
        arguments: 'restore'
    
    - task: DotNetCoreCLI@2
      displayName: 'Run unit tests - $(buildConfiguration)'
      inputs:
        command: 'test'
        arguments: '--no-build --configuration $(buildConfiguration) /p:CollectCoverage=true /p:CoverletOutputFormat=cobertura /p:CoverletOutput=$(Build.SourcesDirectory)/TestResults/Coverage/'
        publishTestResults: true
        projects: '**/*.Tests.csproj'
    
    - task: DotNetCoreCLI@2
      displayName: 'Create code coverage report'
      inputs:
        command: custom
        custom: tool
        arguments: 'run reportgenerator -reports:$(Build.SourcesDirectory)/**/coverage.cobertura.xml -targetdir:$(Build.SourcesDirectory)/CodeCoverage -reporttypes:HtmlInline_AzurePipelines'
    
    - task: PublishCodeCoverageResults@1
      displayName: 'Publish code coverage report'
      inputs:
        codeCoverageTool: 'cobertura'
        summaryFileLocation: '$(Build.SourcesDirectory)/**/coverage.cobertura.xml'
    
    - task: DotNetCoreCLI@2
      displayName: 'Publish the project - $(buildConfiguration)'
      inputs:
        command: 'publish'
        projects: '**/*.csproj'
        publishWebProjects: false
        arguments: '--no-build --configuration $(buildConfiguration) --output $(Build.ArtifactStagingDirectory)/$(buildConfiguration)'
        zipAfterPublish: true
    
    - task: PublishBuildArtifacts@1
      displayName: 'Publish Artifact: drop'
      condition: succeeded()
    

    Esta versão tem como base a configuração existente. Aqui está um resumo das novidades:

    Tarefa do Azure Pipelines Nome de exibição Descrição
    DotNetCoreCLI@2 Instalar as ferramentas do .NET do manifesto local Instala as ferramentas listadas no arquivo de manifesto, dotnet-tools.json
    DotNetCoreCLI@2 Executar testes de unidade – $(buildConfiguration) Executa testes de unidade e também coleta de cobertura de código no formato Cobertura
    DotNetCoreCLI@2 Criar relatório de cobertura de código Converte a saída de Cobertura em HTML
    PublishCodeCoverageResults@1 Publicar o relatório de cobertura de código Publica o relatório para o pipeline

Fazer commit das alterações e enviar o branch por push ao GitHub

Aqui você enviará as alterações por push ao GitHub e verá a execução de pipeline. Lembre-se de que, no momento, você está no branch code-coverage.

Embora não seja necessário, aqui você adicionará e fará commit de cada arquivo separadamente para que cada alteração seja associada a uma mensagem de commit descritiva.

  1. No Visual Studio Code, acesse o terminal.

  2. Adicione e faça commit do arquivo Tailspin.SpaceGame.Web.Tests.csproj, que agora contém uma referência ao pacote coverlet.msbuild:

    git add Tailspin.SpaceGame.Web.Tests/Tailspin.SpaceGame.Web.Tests.csproj
    git commit -m "Add coverlet.msbuild package"
    
  3. Adicione e faça commit do arquivo de manifesto da ferramenta, dotnet-tools.json:

    git add .config/dotnet-tools.json
    git commit -m "Add code coverage"
    
  4. Adicione e faça commit de azure-pipelines.yml, que contém a configuração de build atualizada:

    git add azure-pipelines.yml
    git commit -m "Add code coverage"
    
  5. Envie o branch code-coverage por push ao GitHub.

    git push origin code-coverage
    

Assista aos Azure Pipelines executarem os testes

Aqui, você verá os testes serem executados no pipeline e, em seguida, visualizará os resultados do Azure Test Plans.

  1. No Azure Pipelines, rastreie o build por meio de cada uma das etapas.

  2. Quando a compilação terminar, volte para a página Resumo e selecione a guia Cobertura de código.

    Você vê os mesmos resultados de quando executou os testes localmente.

    A screenshot of Azure Pipelines showing the Code Coverage tab, with code coverage report summary showing 7.7 percent line coverage.

    Como uma etapa opcional, você pode explorar os resultados no Azure Pipelines.

Adicionar o widget ao painel

Na seção anterior, você adicionou o widget Tendência dos Resultados de Teste ao painel, possibilitando que outras pessoas analisem rapidamente as tendências dos resultados dos testes ao longo do tempo.

Aqui, você adicionará um segundo widget que resume a cobertura de código.

  1. Em uma nova guia do navegador, acesse marketplace.visualstudio.com.

  2. Na guia Azure DevOps, pesquise code coverage.

  3. Selecione Code Coverage Widgets (publicados por Shane Davis).

  4. Selecione Get it free.

  5. Na lista suspensa, selecione sua organização do Azure DevOps.

  6. Selecione Instalar.

  7. Volte para o Azure DevOps.

  8. Vá para Overview>Dashboards.

  9. Selecione Editar.

  10. Pesquise Code Coverage e selecione Code Coverage.

    A screenshot of Visual Studio Marketplace showing the Code Coverage widget card.

  11. Arraste Cobertura de Código para a tela.

  12. Selecione o ícone de Engrenagem para configurar o widget.

  13. Mantenha todas as configurações padrão, exceto por:

    • Largura: Insira 2
    • Definição de build: Selecione seu pipeline
    • Medida de cobertura: selecione Linhas
  14. Selecione Salvar.

  15. Selecione Done Editing.

    O widget mostra o percentual de código que seus testes de unidade cobrem.

    A screenshot of Azure DevOps Code Coverage widget showing 8 percent coverage of the sample project.

Agora você tem cobertura de código definida no seu pipeline. Embora sua cobertura de código existente seja baixa, você tem uma linha de base que pode aprimorar ao longo do tempo.

Posteriormente, você pode configurar o coverlet para ver se os testes fornecem um limite mínimo de cobertura. Seu limite pode ser de 30%, 50% ou 80% de cobertura, dependendo dos seus requisitos. A compilação falhará se testes cobrirem uma quantidade inferior a essa.

Remover arquivos de cobertura de código

Lembre-se de que, quando você executou Reportgenerator anteriormente, viu muitos arquivos HTML serem exibidos na pasta CodeCoverage na raiz do projeto.

Esses arquivos HTML não devem ser incluídos no controle do código-fonte e você não precisa mais deles. Embora o arquivo .gitignore do projeto já esteja configurado para ignorar tudo no diretório CodeCoverage, é uma boa ideia excluir esses arquivos para que não sejam adicionados ao seu repositório Git em módulos futuros.

No Visual Studio Code, vá para a janela do terminal e, no diretório raiz do projeto, execute este comando:

rm -rf CodeCoverage/