avatarBob Code

Summary

The website content outlines the process of implementing AltCover for code coverage in Azure DevOps YAML pipelines, particularly for .NET projects running on Linux agents, as an alternative to Coverlet which has limitations on non-Windows platforms.

Abstract

The article addresses the challenge of running code coverage for .NET code on Linux agents within Azure DevOps pipelines, where Coverlet, a commonly used tool, falls short. It introduces AltCover as a solution that works across platforms by weaving IL into assemblies before execution. The author provides a detailed guide on how to integrate AltCover into the CI/CD pipeline, including steps to prepare SonarQube, run .NET tests with AltCover, generate reports with ReportGenerator, and publish the results to Azure DevOps and SonarQube. The process aims to ensure comprehensive code coverage reporting and improve code quality in Linux-based development environments. The article also acknowledges the limitations of AltCover, such as its reliance on a single maintainer and the scarcity of documentation and examples, but emphasizes its advantages, such as compile-time execution and compatibility with different runtimes without the need for updates.

Opinions

  • The author believes that AltCover is a superior alternative to Coverlet for code coverage in .NET projects on Linux agents due to its platform-agnostic approach and compatibility with various runtimes.
  • There is an appreciation for the performance benefits and different tool availability offered by Linux agents compared to Windows agents in Azure DevOps pipelines.
  • The author expresses a need for more documentation and community examples for AltCover, indicating a gap in the current ecosystem that needs to be addressed.
  • The article conveys a positive opinion about the integration of AltCover with Azure DevOps and SonarQube, highlighting its effectiveness in producing detailed code coverage reports.
  • The author values the importance of code coverage as a metric for ensuring code quality and considers AltCover's approach of IL weaving during compile time as a key advantage over runtime-dependent tools like Coverlet.

Code Coverage with AltCover: How to test .Net Code in Azure DevOps YAML pipelines

Problem

How to run code coverage for .Net code with Ubuntu (Linux) agents? Coverlet works with Windows agents but not with Linux agents.

Solution: work with AltCover

Introduction

Code coverage is an important step in software development cycle to ensure code quality.

Using modern CI/CD tools, this process is now automated and part of YAML pipelines that run in tools such as Azure DevOps.

Typically, windows agents run the pipeline and the code coverage is run by Coverlet (a 3rd party tool) and the result formatted and posted in SonarQube.

Nevertheless, when moving to Linux agents — for better performance — it leads to the report failing to generate.

Fortunately, switching to AltCover instead of Coverlet solves the issue.

Since there is little documentation on this topic, we would like to share with the wider community how we managed to solve this transition.

What is AltCover?

As the name suggests, it’s an alternative coverage approach. Rather than working by hooking the .net profiling API at run-time, it works by weaving the same sort of extra IL into the assemblies of interest ahead of execution. This means that it should work pretty much everywhere, whatever your platform, so long as the executing process has write access to the results file. You can even mix-and-match between platforms used to instrument and those under test.

Today, I’m exploring AltCover by Steve Gilham. There are coverage tools that use the .NET Profiling API at run-time, instead, AltCover weaves IL for its coverage.

Objectives

  • Get a detailed Code Coverage report in Azure DevOps
  • Get a full Code Coverage report in SonarQube
Report in ADO
Report in SonarQube

Coverlet Process

1. Run .Net Tests and use DataCollectors to output .Net Tests in openCover files

2. Using reportgenerator, take OpenCover and Outputs them into Corbetura files and Html files

3. Corbertura files provide a detailed .Net Coverage report in Azure DevOps

4. Publish OpenCover Files in SonarQube

What are DataCollectors?

Data collectors perform monitoring operations such as collecting code coverage metrics during test execution.

  • Purpose: One of the primary functions of data collectors like Coverlet is to measure code coverage. Code coverage is a metric used to determine which portions of the codebase are exercised by a set of test cases.
  • Coverage Types: Data collectors can measure different types of code coverage, such as statement coverage, branch coverage, and path coverage. These metrics help identify untested or poorly tested code paths.
  • Usage: Developers and testers use code coverage data to identify areas of the codebase that need more testing, ensuring comprehensive test coverage and helping to uncover potential defects.

Agents: why using Linux agents in your pipeline?

  • More than 30% faster than windows
  • Different tools available

Overall, Linux agents offer flexibility, cost savings, and efficiency for organizations focused on Linux-based development in Azure DevOps pipelines.

Altcover Advantage

- AltCover runs during compile time

  • With Coverlet, it depends on the Runtime, so if there is a new runtime (e.g. .Net7) then support for Coverlet needs to be updated

AltCover disadvantage

- Work of a single individual: Steve Gilham

- Limited Documentation & Code examples

See AltCover GitHub repo: https://github.com/SteveGilham/altcover

Coverlet Process

- Run .Net Tests then Ouput them in openCover Files

- Use reportgenerator to transform the openCover files in Corbertura

- Cobertura then publishes the Corbertura file in Azure DevOps

  • SonarQube publishes the OpenCover file in SonarQube

Code

- task: SonarQubePrepare@5
            displayName: 'SonarQube prepare'
            inputs:
              SonarQube: 'TS SonarQube EE P'
              scannerMode: CLI
              cliSources: $(Build.SourcesDirectory)
              cliProjectName: nameofcliproject.${{ variables.Name }}'
              extraProperties: |
                sonar.projectKey=nameofkey
                sonar.cs.opencover.reportsPaths=$(Build.SourcesDirectory)/coverage.*.opencover.xml


          - task: DotNetCoreCLI@2
            displayName: 'Run tests'
            inputs:
              command: test
              projects: |
                **/ nameofproject2.Tests.csproj
                **/nameofproject1.Tests.csproj
              arguments: '/p:AltCover=true /p:AltCoverForce=true /p:AltCoverReport=$(Build.SourcesDirectory)/coverage.$(ProjectName).opencover.xml  /p:AltCoverAssemblyExcludeFilter=Tests /p:AltCoverAssemblyFilter=Tests|?(project1|| project2) /p:AltCoverAttributeFilter=ExcludeFromCodeCoverage /p:AltCoverVerbosity=Warning'
              
          - task: DotNetCoreCLI@2
            displayName: Restore dotnet tools
            inputs:
              command: custom
              custom: tool
              arguments: restore

          - script: |
              dotnet reportgenerator -reports:$(Build.SourcesDirectory)/coverage.*.opencover.xml '-targetdir:$(Build.SourcesDirectory)/' '-reporttypes:TextSummary;Cobertura'
            displayName: Generate report
            
          - task: PublishCodeCoverageResults@1
            displayName: 'Publish code coverage report'
            inputs:
              codeCoverageTool: 'cobertura'
              summaryFileLocation: '$(Build.SourcesDirectory)/Cobertura.xml'

          - task: SonarQubeAnalyze@5
            displayName: 'SonarQube analyze'

          - task: SonarQubePublish@5
            displayName: 'SonarQube publish results'
            inputs:
              pollingTimeoutSec: '300'

Code explained: #1 Prepare SonarQube

The * ensures that all files in the directory are included in the code coverage

Result = SonarQube will create reports based on all opencover.xml files found in the mentioned directory

Code explained: #2 Run DotNet Tests

Result = Tests are run and converted by AltCover into opencover.xml files

Full Arguments string:

arguments: ‘/p:AltCover=true /p:AltCoverForce=true /p:AltCoverReport=$(Build.SourcesDirectory)/coverage.$(ProjectName).opencover.xml /p:AltCoverAssemblyExcludeFilter=Tests /p:AltCoverAssemblyFilter=Tests|?(nameofproject1|| nameofproject2||) /p:AltCoverAttributeFilter=ExcludeFromCodeCoverage /p:AltCoverVerbosity=Warning’

Arguments string explained:

  1. /p:AltCover=true (use AltCover package)
  2. /p:AltCoverForce=true (Use AltCover even if other packages are in place)
  3. /p:AltCoverReport=$(Build.SourcesDirectory)/coverage.$(ProjectName).opencover.xml (OutPut test project in opencover.xml)
  4. /p:AltCoverAssemblyExcludeFilter=Tests (exclude filter: all tests projects)
  5. /p:AltCoverAssemblyFilter=Tests|?( nameofproject1|| nameofproject2) (but include these)
  6. /p:AltCoverAttributeFilter=ExcludeFromCodeCoverage (apply exclude filter)
  7. /p:AltCoverVerbosity=Warning (log level)

Code explained: #3 ReportGenerator

Result = transform OpenCover File into Cobertura

Code explained: #4 Publish Cobertura

Cobertura is a reporting tool. It helps developers and teams assess the quality of their code by visualising test coverage and identifying areas that require additional testing.

Its open-source nature and integration capabilities make it a valuable asset in the development and testing process.

it is also called a parser because it takes data and parses it into a nice report.

Code explained: #5 SonarQube analyse & publish

Links to Resources

Alt Cover Official documentation

Medium

Dotnet
Testing
Azure Devops
Yaml
Pipeline
Recommended from ReadMedium