-
Notifications
You must be signed in to change notification settings - Fork 1
Working with Code Coverage
This guide shows how to run code coverage for a project that uses the generator, and how to keep generated code out of your coverage numbers.
Every type the generator emits is annotated with [GeneratedCode("Atc.Rest.Api.SourceGenerator", "<version>")]. That attribute alone doesn't exclude anything from coverage β it just marks the code as generated. To keep generated models, endpoints, results, and DI extensions out of your coverage report, you need one of:
| Option | Scope | How |
|---|---|---|
π·οΈ excludeFromCodeCoverage marker option
|
This project's generated output only | Adds [ExcludeFromCodeCoverage] next to [GeneratedCode] on every generated type |
βοΈ .runsettings attribute exclusion
|
Any generated/compiler-generated code, project-wide | Tells the coverage collector to skip anything carrying [GeneratedCode], [ExcludeFromCodeCoverage], or [CompilerGenerated]
|
They're complementary β the marker option needs no test-project setup and works the moment you enable it; the .runsettings file also silently covers hand-written code you've explicitly marked [ExcludeFromCodeCoverage], and any other source generator's [GeneratedCode] output in the same solution.
Test projects need the Microsoft.Testing.Extensions.CodeCoverage package (already wired into this repo's test/Directory.Build.props for every test project; add it yourself for consumer projects):
dotnet add package Microsoft.Testing.Extensions.CodeCoverageThen run:
dotnet test --coverageThis produces a .coverage file under TestResults/. Useful flags:
# Cobertura XML instead of the binary .coverage format (for CI / report tooling)
dotnet test --coverage --coverage-output-format cobertura
# Custom output path
dotnet test --coverage --coverage-output ./coverage/results.cobertura.xml
# Apply exclusion rules from a settings file (see below)
dotnet test --coverage --coverage-settings coverage.runsettingsπ‘ Tip: Pipe Cobertura output into ReportGenerator (
dotnet tool install -g dotnet-reportgenerator-globaltool) to get an HTML coverage report.
Set excludeFromCodeCoverage: true in any marker file β .atc-rest-api-server, .atc-rest-api-server-handlers, or .atc-rest-api-client:
{
"generate": true,
"excludeFromCodeCoverage": true
}Every generated type that carries [GeneratedCode] now also gets [ExcludeFromCodeCoverage]:
// <auto-generated />
#nullable enable
using System.CodeDom.Compiler;
using System.Diagnostics.CodeAnalysis;
using Microsoft.Extensions.DependencyInjection;
namespace PetStore;
[GeneratedCode("Atc.Rest.Api.SourceGenerator", "1.0.341")]
[ExcludeFromCodeCoverage]
public static class ServiceCollectionEndpointHandlerExtensions
{
...
}[ExcludeFromCodeCoverage] isn't valid on every declaration kind β the C# compiler only allows it on classes, structs, records, constructors, methods, properties, and events. Interfaces, enums, and delegates (e.g. IEndpointDefinition, handler interfaces) keep [GeneratedCode] without it; there's nothing to exclude on a type with no executable body.
Default is false β existing projects are unaffected until you opt in. Set it independently per marker file; a Contracts project can exclude generated code from coverage while a hand-written Domain project doesn't (or vice versa).
π‘ See Marker Files for the full option reference across all three marker types.
If you'd rather exclude generated code project-wide β without touching every marker file, and covering any other source generator's output too β configure the Microsoft Code Coverage collector to skip specific attributes.
Create coverage.runsettings:
<?xml version="1.0" encoding="utf-8"?>
<RunSettings>
<DataCollectionRunSettings>
<DataCollectors>
<DataCollector friendlyName="Code Coverage" uri="datacollector://microsoft/CodeCoverage/2.0">
<Configuration>
<CodeCoverage>
<Attributes>
<Exclude>
<!-- Universal opt-out β respected by all coverage tools -->
<Attribute>System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute</Attribute>
<!-- Source generators, Dataverse Model Builder, ApiGenerator, etc. -->
<Attribute>System.CodeDom.Compiler.GeneratedCodeAttribute</Attribute>
<!-- C# compiler internals: async state machines, lambdas, iterators, records -->
<Attribute>System.Runtime.CompilerServices.CompilerGeneratedAttribute</Attribute>
</Exclude>
</Attributes>
</CodeCoverage>
</Configuration>
</DataCollector>
</DataCollectors>
</DataCollectionRunSettings>
</RunSettings>Then reference it when running tests:
dotnet test --coverage --coverage-settings coverage.runsettingsBecause every type this generator emits already carries [GeneratedCode] unconditionally, excluding System.CodeDom.Compiler.GeneratedCodeAttribute removes all generated output from coverage β no marker file changes needed. The other two attributes are there for completeness:
-
ExcludeFromCodeCoverageAttributeβ hand-written code you've explicitly opted out (or generated code withexcludeFromCodeCoverage: trueset, redundantly β either attribute alone is enough) -
CompilerGeneratedAttributeβ compiler-synthesized members (async state machines, closures, primary constructors, record equality members) that aren't yours to test either
β οΈ ExcludingGeneratedCodeAttributeproject-wide also excludes output from any other source generator in the solution (EF Core, MediatR, etc.) that follows the same convention. Use the marker option instead if you only want this generator's output excluded.
| Scenario | Use |
|---|---|
| Only want this generator's output excluded, no build/CI changes | π·οΈ excludeFromCodeCoverage marker option |
| Want generated code excluded across the whole solution, including other generators | βοΈ .runsettings
|
CI pipeline already has a shared .runsettings for other exclusion rules |
βοΈ .runsettings β add the three attributes to your existing file |
| Different exclusion policy per project (Contracts excluded, Domain not) | π·οΈ excludeFromCodeCoverage marker option, set per marker file |
They can also be combined β a .runsettings exclusion is a safety net that keeps working even if a marker file's excludeFromCodeCoverage is left at its false default.
- Marker Files β Full marker file option reference
-
Working with Configuration β
ApiGeneratorOptions.jsonand CLI-based configuration
π Home
- πΌ FAQ Business Value
- π Getting Started with Basic
- π οΈ Getting Started with CLI
- π Migration Guide
- π Working with OpenAPI
- π οΈ Working with CLI
- π How-To Guides
- π Working with Security
- π¦ Working with Rate Limiting
- π Working with Resilience
- ποΈ Working with Caching
- π’ Working with Versioning
- β Working with Validations
- π Working with Webhooks
- βοΈ Working with Aspire
- π£οΈ Working with Endpoint Definitions
- π Working with Multi-Part Specs
- π§ͺ Working with Code Coverage
- π¦ Working with TypeScript Client
- πͺ Showcase Demo
- π§ͺ Working with E2E Testing
- βοΈ Working with Configuration
- π Marker Files
- π API Reference
- π Analyzer Rules
- β FAQ and Troubleshooting
- πΊοΈ Roadmap
- π§ Development Notes
- π¦ GitHub Repository
- π₯ NuGet Package
- π Report Issues