The Standard for .NET Code Coverage

Modern Code Coverage
For Modern .NET

Coverlet is a cross-platform code coverage framework for .NET, supporting line, branch, and method coverage. Integrate it seamlessly into your test runner of choice in seconds.

Core Capabilities

Coverlet provides powerful, modular tools designed to fit any unit testing setup in the .NET ecosystem.

Cross-Platform

Run your coverage tools smoothly across Windows, Linux, and macOS. Fully optimized for containerized Docker build agents and CI/CD workflows.

Multiple Drivers

Choose how you run coverage: as an MSBuild task, a VSTest data collector integration, or a standalone cross-platform .NET global tool.

Granular Metrics

Collect precise coverage metrics including Line coverage, Branch coverage, and Method coverage. Know exactly which paths are tested.

Performance & DevX

Why Choose Coverlet?

Coverlet makes code coverage painless. It is lightweight, fast, and integrates natively into the Microsoft unit testing ecosystem.

Zero Custom Configuration

For standard templates, just run the command. Coverlet works immediately without complex XML configuration files.

Format Agnostic Outputs

Export reports in Cobertura, JSON, LCOV, or OpenCover. Perfect for visualizers like ReportGenerator or SonarQube.

Active OSS Support

Backed by a large community under the .NET Foundation, ensuring long-term compatibility and security updates.

CLI Test Output dotnet test
# Running tests and collecting coverage
dotnet test --collect:"XPlat Code Coverage"

Test run for UnitTests.dll (.NET Core)
Passed! - Failed: 0, Passed: 142, Skipped: 0

Calculated Coverage Results:
-----------------------------------------
| Module | Line | Branch | Method |
-----------------------------------------
| Core.Lib | 94.2% | 88.7% | 100% |
-----------------------------------------

✓ Coverage collection completed successfully.

Quick Installation

Choose your preferred driver integration and get coverage setup in seconds.

dotnet add package coverlet.collector

The **VSTest Collector** (called `coverlet.collector`) is the modern way to retrieve code coverage. It hooks directly into the Visual Studio / VSTest runner process without modifying MSBuild assembly outputs.

Usage Examples

Run coverage commands, export report formats, and configure output layouts easily.

CLI Commands Exporting Cobertura or OpenCover
# 1. Run tests with VSTest Collector (output Cobertura report)
dotnet test --collect:"XPlat Code Coverage"

# 2. Run tests with MSBuild Integration (custom output format and output file)
dotnet test /p:CollectCoverage=true /p:CoverletOutputFormat=cobertura /p:CoverletOutput=./TestResults/

# 3. Exclude specific namespaces using MSBuild filters
dotnet test /p:CollectCoverage=true /p:Exclude="[System.*]*"
913M+
NuGet Downloads
3.2k+
GitHub Stars
400+
Forks
100%
Free & OSS
Deep Dive

Exploring Code Coverage in Modern .NET with Coverlet

1. Introduction to Code Coverage in .NET

Software quality assurance in modern cloud-native systems is a multi-dimensional challenge. For development teams building enterprise-grade applications, unit testing represents the first line of defense against code regressions, functional bugs, and security vulnerabilities. However, simply writing tests is not enough; teams need a reliable, quantitative metric to gauge the thoroughness of their test suites. This is where code coverage comes into play. Code coverage measures the percentage of your application's source code that is executed when your test suite runs. By identifying untested code paths, branch conditions, and methods, it highlights gaps in your test coverage, giving developers the confidence to refactor and expand codebase functionalities aggressively.

Historically, code coverage in the .NET ecosystem was dominated by heavy, proprietary, Windows-only tools. These legacy solutions required manual installations, custom configurations, and expensive licensing fees, making them highly incompatible with the modern, lightweight, cross-platform developers' workflows. The introduction of .NET Core changed the paradigm, demanding a testing infrastructure that could run seamlessly across Windows, macOS, and Linux distributions, as well as inside containerized Docker build agents.

In response to this demand, Coverlet emerged as the standard, open-source, cross-platform code coverage framework for .NET. Hosted under the .NET Foundation, Coverlet has grown to become the standard choice for modern testing pipelines, boasting hundreds of millions of downloads on NuGet. It supports line coverage, branch coverage, and method coverage, hooking directly into the build and test engines to collect high-fidelity metrics with minimal performance overhead. Integrating coverlet-coverage into your software development lifecycle ensures that your teams can track, analyze, and enforce code quality standards consistently across all deployment environments.


2. Core Features of the Coverlet Ecosystem

Coverlet’s design is modular, lightweight, and deeply integrated into the .NET SDK. Unlike legacy tools that require post-processing of compiled binaries, Coverlet performs dynamic IL (Intermediate Language) instrumentation. When tests are executed, coverlet-coverage intercepts the loading of target assemblies, rewriting the IL in memory or on disk to insert tracking hooks (counters) at every branch, line, and method entry point. As tests run, these counters are incremented. Once execution completes, Coverlet aggregates the counter data to calculate precise coverage statistics.

Let’s explore the three primary dimensions of coverage that Coverlet tracks:

  • Line Coverage: This metric measures the percentage of executable lines of code that were touched by at least one test. It is the most basic form of coverage and provides a high-level overview of which parts of the codebase were visited.
  • Branch Coverage: Often considered a more rigorous metric, branch coverage checks whether every decision point in the code (such as if, else, switch statements, and conditional expressions) has been evaluated under both true and false conditions. High branch coverage is critical for verifying complex business logic and edge cases.
  • Method Coverage: This metric tracks the percentage of methods within your classes and structs that were called during the test run. While a method might only have partial line coverage, knowing whether it was invoked at all is useful for locating dead code or completely neglected modules.

One of Coverlet's greatest strengths is its ability to export coverage reports in multiple industry-standard formats. Whether you are using local visualizers, cloud dashboard widgets, or third-party analysis platforms, Coverlet has you covered. It natively supports Cobertura (the default format for many modern CI/CD reporters), OpenCover, LCOV, JSON, and TeamCity formats. This versatility makes it trivial to feed Coverlet reports into tools like SonarQube, Azure Pipelines, GitHub Actions, or local HTML report builders.


3. Benefits of Modern Dynamic Instrumentation

The shift from static analysis or compiler-based profiling to Coverlet's dynamic instrumentation offers numerous benefits for software engineering teams:

  • True Cross-Platform Capability: Because Coverlet runs within the .NET runtime host, it behaves identically whether it is executed on a developer's macOS laptop, a Windows workstation, an Alpine Linux Docker container, or an ephemeral build agent in the cloud. This consistency eliminates "works on my machine" discrepancies during quality gates.
  • Developer Experience (DevX): Developers do not need to install local desktop agents or configure IDE-specific add-ons to gather coverage. By adding a simple package reference to the test project, coverage metrics are generated automatically during standard dotnet test invocations.
  • Low Overhead: Coverlet’s instrumentation engine is highly optimized. By rewriting IL directly and using lock-free thread-safe counters, it minimizes the performance penalty on test execution speeds, keeping CI feedback loops fast.
  • Flexible Integration Drivers: Coverlet does not force a single way of working. It provides three distinct drivers—an MSBuild task, a VSTest data collector, and a global CLI tool—allowing developers to choose the integration model that best fits their project's build patterns and CI environment.
  • Community-Backed & Standards-Compliant: Being a .NET Foundation project ensures that Coverlet is maintained in alignment with the official .NET roadmap. It receives continuous updates to support new C# language features, compiler optimizations, and runtime versions.
"Code coverage metrics provide developers the confidence to refactor code aggressively, knowing that any regressions in critical paths will be instantly flagged by automated test runs."

4. Installation Guide & Driver Configurations

To begin collecting code coverage, you must select the appropriate integration driver for your workspace. While all drivers share the same underlying coverage engine and produce the same output formats, they differ in how they are invoked and integrated into your build process.

To select the ideal driver, review the options below and choose the one that matches your testing structure. To select packages, download releases, and access direct download configurations, visit the Coverlet Download Page.

Recommended Practice: For most new solutions, we recommend starting with the VSTest Data Collector. It offers the cleanest separation of testing and build orchestration.

A. VSTest Data Collector (Recommended)

The VSTest Data Collector integration is the most modern and recommended way to run Coverlet. It hooks directly into the VSTest (Visual Studio Test) engine, collecting coverage metrics out-of-process. This out-of-process execution prevents conflicts with assembly loading and does not pollute your bin/obj build outputs.

To install the VSTest collector, add the NuGet package to your unit test project:

dotnet add package coverlet.collector

Once installed, you can collect coverage using the standard dotnet test command by appending the collect flag:

dotnet test --collect:"XPlat Code Coverage"

This command triggers the collector and outputs a Cobertura coverage file (usually named coverage.cobertura.xml) inside a dynamically generated GUID directory under TestResults/.

B. MSBuild Integration

The MSBuild integration inserts custom targets directly into your project's compile and test cycles. It is ideal for teams that want to configure coverage rules directly within their .csproj files or build scripts.

To install the MSBuild integration, run:

dotnet add package coverlet.msbuild

With this package referenced, you run coverage by passing MSBuild parameters to the test runner:

dotnet add package coverlet.msbuild

With this package referenced, you run coverage by passing MSBuild parameters to the test runner:

dotnet test /p:CollectCoverage=true

This driver offers rich MSBuild properties for customization. For example, you can specify output formats and target paths directly on the command line:

dotnet test /p:CollectCoverage=true /p:CoverletOutputFormat=cobertura /p:CoverletOutput=./artifacts/coverage.xml

C. Console Global CLI Tool

The Console Global Tool is a standalone CLI version of Coverlet. It is particularly useful when you want to measure the coverage of pre-compiled assemblies (DLLs) without referencing packages inside the test project, or when writing custom build orchestration scripts.

To install the global tool, execute:

dotnet tool install --global coverlet.console

Once installed, you can run coverage on any compiled DLL by executing the coverlet command:

coverlet /path/to/test/assembly.dll --target "dotnet" --targetargs "test /path/to/test/project.csproj --no-build"

5. Advanced Usage and Configuration Examples

Beyond simple package installation, Coverlet supports advanced configurations to handle complex, enterprise-scale codebases. In large applications, you often want to exclude test assemblies, third-party libraries, generated code, or infrastructure layers from your coverage reports to avoid skewing the metrics.

Advanced Filters: Filters are evaluated sequentially. Make sure to define them precisely to avoid omitting required production classes.

Filtering Coverage Assemblies

You can specify include and exclude filters using wildcard patterns. Filters are structured as [AssemblyFilter]TypeFilter, where wildcards can be applied to both the assembly name and the namespace/type.

Assembly-Level Wildcards

By utilizing wildcard parameters at the assembly level, developers can target or ignore entire packages. This is particularly useful for avoiding coverage reports on utility modules or third-party wrappers.

Type & Namespace Exclusions

Fine-grained exclusions can also be defined to bypass specific classes or entire namespaces. Coverlet will omit these symbols entirely from code profiling steps.

Example using VSTest Collector (runsettings): Create a .runsettings file in your solution root:

<RunSettings>
  <DataCollectionRunSettings>
    <DataCollectors>
      <DataCollector friendlyName="XPlat Code Coverage">
        <Configuration>
          <Exclude>[*.Tests]*</Exclude>
          <ExcludeByAttribute>Obsolete,CompilerGeneratedAttribute,ExcludeFromCodeCoverageAttribute</ExcludeByAttribute>
          <Format>cobertura</Format>
        </Configuration>
      </DataCollector>
    </DataCollectors>
  </DataCollectionRunSettings>
</RunSettings>

Then, execute your tests pointing to the settings file:

dotnet test --settings .runsettings

Enforcing Coverage Thresholds

For CI/CD gates, Coverlet allows you to enforce coverage thresholds. If the collected coverage drops below a specified percentage, the build runner fails the execution. This ensures that new pull requests cannot merge code that lacks appropriate test coverage.

Threshold Target Configurations

Configure whether quality thresholds should validate line, branch, or method coverage metrics in a combined format or independently.

Threshold Format Customizations

Set parameters to determine whether thresholds are computed per individual class, per compiled assembly, or as a global sum.

Using MSBuild:

dotnet test /p:CollectCoverage=true /p:Threshold=80 /p:ThresholdType=branch /p:ThresholdFormat=total

If the overall branch coverage is below 80%, the build fails with an error.


6. CI/CD Integration Patterns

Automating code coverage tracking inside your CI/CD pipelines ensures that quality gates are run on every commit. Let’s look at how to set up Coverlet in popular environments.

GitHub Actions Workflow

In GitHub Actions, you can run tests with Coverlet, then use third-party actions to generate visual summaries or upload results to external dashboards.

Workflow Configuration Syntax

Declare test execution steps inside your YAML workflow files to invoke Coverlet collectors during automated test passes.

Uploading Coverage to Third-Party Panels

Combine the outputs with GitHub actions designed to export cobertura reports directly into PR visual reviews.

name: Build and Test on: [push, pull_request] jobs: test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Setup .NET uses: actions/setup-dotnet@v4 with: dotnet-version: '8.0.x' - name: Run Tests run: dotnet test --configuration Release --collect:"XPlat Code Coverage"

Azure DevOps Pipelines

Azure Pipelines natively understands Cobertura reports and can display tab summaries directly inside the build results page.

Pipeline YAML Tasks

Configure standard script tasks in Azure pipelines to perform the build and run standard coverage parameters.

Publishing Cobertura Summaries

Use standard publishing tasks to read the resulting cobertura xml reports, displaying coverage percentages directly within the Devops tab.

trigger: - main pool: vmImage: 'ubuntu-latest' steps: - task: UseDotNet@2 inputs: version: '8.x' - script: dotnet test --collect:"XPlat Code Coverage" displayName: 'Execute Tests and Collect Coverage'

7. Generating Visual Reports with ReportGenerator

While raw Cobertura XML files are perfect for machine reading, they are virtually impossible for human developers to scan. To solve this, you can use the excellent ReportGenerator tool, which compiles multiple XML files into beautiful, interactive, self-contained HTML dashboards.

To generate a local visual report:

  1. Install the ReportGenerator tool globally:
    dotnet tool install --global dotnet-reportgenerator-globaltool
  2. Run Coverlet to produce the Cobertura XML:
    dotnet test --collect:"XPlat Code Coverage"
  3. Run ReportGenerator on the output:
    reportgenerator -reports:"**/coverage.cobertura.xml" -targetdir:"coveragereport" -reporttypes:Html

Open the coveragereport/index.html file in your preferred web browser to view detailed statement-by-statement coverage highlightings.


8. Troubleshooting & Frequently Asked Questions (FAQs)

Why is my coverage output reporting 0% or empty results?

This is a common issue that typically stems from assembly loading sequences. Ensure that you are targetting a test project, and that the test project references the primary logic project as a Project Reference. If you are using coverlet.collector, verify that you have passed the correct parameter --collect:"XPlat Code Coverage" (case-sensitive) and that the collector library is correctly loaded in the build directory.

How does Coverlet handle async/await state machines?

The C# compiler compiles async methods into complex state machine structs behind the scenes, creating hidden branches and error paths. Coverlet includes dedicated filtering logic to reconstruct async call trees and clean up compile-generated artifacts, ensuring that your branch metrics reflect your true business logic rather than compiler optimizations.

Can I combine coverage results from multiple test projects?

Yes! In large solutions with separate unit and integration test projects, you can output reports to a shared directory. When running ReportGenerator, pass the directory path containing all Cobertura reports, and it will automatically merge the results into a single consolidated view.



10. Conclusion & Best Practices

Maintaining comprehensive test coverage is not about chasing a perfect 100% score; it is about building a reliable feedback mechanism that helps your development team move fast without breaking existing capabilities. By integrating coverlet-coverage into your software pipelines, you establish a lightweight, reliable, and standardized metrics system. Whether you run it as an out-of-process VSTest collector, reference it via MSBuild targets, or coordinate it through CLI command tools, Coverlet fits seamlessly into the modern C# developer experience.

For full packages download support and releases update setups, visit our official Coverlet Download Page.

C

Coverlet Documentation Team

The official open-source community contributors and architects of the Coverlet code coverage engine under the .NET Foundation.

← Previous Page Home Page Next Page → Download Coverlet

Frequently Asked Questions

Get answers to common queries about using and configuring Coverlet.

What is Coverlet?

Coverlet is a cross-platform code coverage framework for .NET, supporting line, branch, and method coverage. It runs on Windows, Linux, and macOS, providing detailed data on what parts of your assembly have been executed by your tests.

Which coverage formats are supported?

Coverlet is format-agnostic. It can export results to Cobertura (the default format), OpenCover, LCOV, or its custom Coverlet JSON format. This compatibility makes it trivial to integrate with visualization systems like ReportGenerator or SonarQube.

How do I exclude specific files or namespaces?

You can use standard filter syntaxes using MSBuild parameters or VSTest configuration. For example, using /p:Exclude="[Project.Tests]*" will ignore classes compiled under the tests project, ensuring only your primary logic is tracked.

Is Coverlet compatible with all unit test frameworks?

Yes. Coverlet supports all standard test frameworks including xUnit, NUnit, and MSTest. Since it hooks into VSTest / MSBuild levels, it is completely decoupled from the specific runner syntax.

Community & Support

Get involved with the Coverlet project or find help when integrating it.

GitHub Repository

Report bugs, submit PRs, and explore documentation on the official GitHub repository page.

View Releases & Code

NuGet Ecosystem

Download stable packages and track releases directly inside the NuGet package registry.

Search Packages