# Coverlet for .NET: four drivers, one coverage engine, and the MTP split

> Coverlet is a cross platform code coverage framework for .NET with line, branch and method coverage. The interesting part is not the metric but the driver you pick: coverlet.MTP, coverlet.collector, coverlet.msbuild and coverlet.console do not share the same test runner, and the README says two of them cannot be used with the Microsoft Testing Platform at all.

**coverlet-coverage/coverlet** — Cross platform code coverage for .NET

- Repository: https://github.com/coverlet-coverage/coverlet
- Stars: 3,172 · Forks: 398
- Language: C#
- License: MIT
- Published: 2026-09-24 · Updated: 2026-09-24 · Language: en
- Canonical page: https://hysenlabs.com/projects/coverlet-coverage-coverlet

## What Coverlet actually covers, and who ends up using it

Coverlet measures line, branch and method coverage for .NET code. It runs on .NET Framework on Windows and on .NET Core across supported platforms, which is what the cross platform label in the README refers to. The audience is narrow and specific: teams whose tests live in SDK-style projects and who want a coverage number produced by the same CLI they already use to run tests. The README is explicit that Coverlet only supports modern SDK-style projects, so a legacy .csproj with an explicit file list is out of scope before you install anything.

The framework is distributed as four separate NuGet packages rather than one. That is the first decision a new user faces, and it is not cosmetic. coverlet.MTP is an extension for projects running on the Microsoft Testing Platform. coverlet.collector and coverlet.msbuild plug into VSTest and MSBuild respectively. coverlet.console is a global tool for standalone integration tests. Choosing the wrong one does not degrade gracefully; the README states the collector and msbuild packages cannot be used with MTP at all.

## The instrumentation path: bytecode rewriting at test time

The repository topics list bytecode and instrumentation, and the README's driver table is the visible surface of that design. Coverlet does not ask you to add attributes to production code or maintain a parallel instrumented build. The coverage work happens around the test run: the driver loads the assemblies under test, rewrites them at the bytecode level, executes the test runner, and writes a report. That is why the global tool's usage section insists the test runner invocation must not involve a recompilation of the unit test assembly, warning that otherwise no coverage result will be generated. If the assembly is rebuilt after instrumentation, the instrumented copy is not the one that ran.

The report formats are json, lcov, opencover and cobertura. For coverlet.MTP the README says reports are generated in the test results directory and that json and cobertura are the defaults, so a first run produces two files rather than one. Output is written after the test process completes; there is no streaming coverage endpoint documented in the README.

One consequence worth stating plainly: because instrumentation happens on the compiled assembly, the coverage you get reflects the build that ran, not the source tree. Deterministic build support is listed as a main content link in the README, which signals that reproducible builds interact with instrumentation in ways the project has had to address separately.

## Installing Coverlet and getting a first report out of a test project

The README's quick start routes through the Microsoft Testing Platform driver, so that is the shortest path if your test project already uses MTP. Add the package to the test project:

```bash
dotnet add package coverlet.MTP
```

The README adds a note that this package belongs only in test projects using Microsoft.Testing.Platform as the runner, not the traditional VSTest runner. Then enable collection with the --coverlet flag:

```bash
dotnet test --coverlet
```

After the command runs, the README states coverage report files appear in the test results directory, in json and cobertura by default. To narrow what is measured, pass filters. The README's example switches the format to cobertura and excludes xunit types:

```bash
dotnet run --project <your-test-project> --coverlet --coverlet-output-format cobertura --coverlet-exclude "[xunit.]"
```

The available options listed are --coverlet, --coverlet-output-format, --coverlet-include, --coverlet-exclude and --coverlet-include-test-assembly. Requirements for this driver are the .NET 8.0 SDK or newer and a test project configured for Microsoft Testing Platform.

If you would rather not touch the test project at all, the global tool installs separately:

```bash
dotnet tool install --global coverlet.console
```

The README states the global tool requires .NET 8.0 or above. Its invocation takes the test assembly path plus --target and --targetargs:

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

The --no-build flag is there so the test assembly is not rebuilt, which the README ties directly to whether coverage is produced at all.

## Where Coverlet breaks: MTP, VSTest and the .NET 10 dotnet test path

The sharpest limitation is a compatibility wall between drivers. The README carries a warning that coverlet.collector and coverlet.msbuild cannot be used with the Microsoft Testing Platform, and calls this out as especially relevant for the native dotnet test integration introduced with .NET 10. The stated reason is architectural: both packages rely on VSTest infrastructure, while MTP uses a different test execution architecture. This is not a configuration problem you can work around with a flag. If your tests moved to MTP, those two packages are the wrong tool and coverlet.MTP is the replacement.

A second constraint sits in the global tool. Because it wraps an external test runner, the runner invocation must not recompile the test assembly. A build step inside your targetargs silently produces no coverage rather than an error, which is a poor failure mode for a CI pipeline. The README also links a known issue titled "VSTest stops process execution early (dotnet test)" from the global tool section, so process lifetime is a documented area of friction there.

.NET Framework is supported only on Windows, and the README links a KnownIssues entry about BadImageFormatException on .NET Framework 4.7.x and 4.8.x. Finally, the README warns that the documentation reflects the current repository state rather than released features and points readers to the changelog to check whether a documented option has shipped. Treat the README as a description of master, not of the version in your package cache.

## Coverlet against the built-in dotnet test collector

The obvious alternative is the coverage collector that ships with the .NET SDK, which records coverage through the same VSTest data collector pipeline that coverlet.collector plugs into. The practical difference is where the data goes. The built-in collector emits a .coverage binary that you need a separate tool to open, while Coverlet writes json, lcov, opencover or cobertura from the same run. Cobertura and lcov are the formats most CI dashboards and pull request annotations consume directly, so the difference is often one less conversion step rather than a difference in what is measured.

A second difference is the filter model. Coverlet's MTP options take assembly and type filters inline, as in the --coverlet-exclude "[xunit.]" example, and there is a --coverlet-include-test-assembly switch for the cases where you do want the test project measured. That is a driver-level control rather than a runsettings file edit.

The trade-off is coupling. The built-in collector travels with the SDK and needs no package reference; Coverlet is a package you add and a driver you choose correctly. If your team already standardizes on runsettings-based coverage and never needs an XML report, the built-in path is less to maintain. If a report has to land in a CI system that reads cobertura, Coverlet removes a step.

## Maintenance, versioning and what the MIT licence leaves you

The repository is not archived, and the last push was on 2026-09-23, one day before this article's reference point, so the project is being worked on. Recent releases are v10.0.1 on 2026-05-18, v10.0.0 on 2026-04-17 and v8.0.1 on 2026-03-17. Note the version sequence: v8.0.1 in March, then v10.0.0 in April. The README does not explain the jump, and the changelog is the place to look for it before you pin a version. Because the README documents repository state rather than released state, a feature you read about may not exist in the package you install.

The upgrade cost is concentrated in the driver, not the reporting. Moving from coverlet.collector to coverlet.MTP is not a version bump; it changes the test runner your project uses, and the README's warning makes clear the two are mutually exclusive. Budget for that as a migration, not an upgrade. Within a driver, the options are CLI flags or MSBuild properties, so a version change is mostly a matter of checking the changelog for renamed or removed options.

Coverlet is MIT licensed, which the README states directly. That is permissive and imposes no copyleft obligation on your own code. It says nothing about the licences of the packages Coverlet itself depends on; the repository carries a THIRD-PARTY-NOTICES.txt at the top level, and that file is where a dependency review should start. Nothing here is legal advice.

## Conclusion

Adopt Coverlet if your test projects are SDK-style and you want coverage without leaving the dotnet CLI. Do not adopt it for non-SDK project files, and do not pick coverlet.collector or coverlet.msbuild if your tests already run on the Microsoft Testing Platform, because the README states both rely on VSTest infrastructure and are incompatible with MTP. Before wiring it into CI, run the driver once locally and confirm the report directory and format, then check Documentation/Changelog.md to see whether the option you intend to use is in a released version or only in the repository's current state.

## FAQ

### How do I install Coverlet in Visual Studio?

The README does not give a Visual Studio installation procedure. It lists a Visual Studio Add-In as a main content link, and the documented installation paths are NuGet package references such as dotnet add package coverlet.MTP or the global tool via dotnet tool install --global coverlet.console.

### How do I use coverlet.collector?

The README does not document coverlet.collector usage in the text provided; it lists the package in the driver table and links a DriversFeatures document that compares the drivers. What the README does state is that coverlet.collector relies on VSTest infrastructure and cannot be used with the Microsoft Testing Platform.

### How do I use Coverlet in Visual Studio 2022?

The README does not describe a Visual Studio 2022 workflow. The documented entry points are CLI based: dotnet test --coverlet for Microsoft Testing Platform projects, or the coverlet global tool with --target and --targetargs for standalone runs.

## Sources

- [coverlet-coverage/coverlet on GitHub](https://github.com/coverlet-coverage/coverlet)
- [Issues](https://github.com/coverlet-coverage/coverlet/issues)
- [License: MIT](https://github.com/coverlet-coverage/coverlet/blob/master/LICENSE)
- [README](https://github.com/coverlet-coverage/coverlet/blob/master/README.md)
- [Releases](https://github.com/coverlet-coverage/coverlet/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/coverlet-coverage-coverlet
