Skip to content

codecharter coverage

Tests mit Coverage-Messung ausführen und gegen eine Mindest-Line-Coverage prüfen, konfiguriert in .codecharter/config.yml und als maschinenlesbares JSON berichtet.

codecharter coverage [root] [optionen]

codecharter coverage sucht die Testprojekte unterhalb von root (standardmäßig das aktuelle Verzeichnis), führt sie mit Coverage-Messung aus, führt die Ergebnisse zusammen und lässt den Build fehlschlagen, sobald die Line-Coverage unter den geforderten Mindestwert fällt. Derselbe Lauf meldet zusätzlich jede ungedeckte Region mit Quelltext-Ausschnitt, sodass Sie genau sehen, welchen Zeilen ein Test fehlt.

Damit ist die zweite Hälfte des Quality Gates abgedeckt: analyze beantwortet "ist der Code sauber geschrieben", coverage beantwortet "ist er tatsächlich getestet".

Voraussetzung

Die Messung läuft über den Collector XPlat Code Coverage, der das Paket coverlet.collector in jedem Testprojekt benötigt:

<PackageReference Include="coverlet.collector" Version="6.*" PrivateAssets="all" />

Ein Testprojekt ohne dieses Paket führt seine Tests zwar aus, liefert aber keine Coverage-Daten. Der Lauf benennt jedes betroffene Projekt und gibt die Zeile aus, die Sie ergänzen müssen.

Schnellstart

# Repository gegen den konfigurierten Mindestwert prüfen
codecharter coverage

# Einen Ordner gegen 90 % prüfen
codecharter coverage src --min-coverage 90

# Ergebnisse eines bereits gelaufenen Testlaufs auswerten
codecharter coverage --skip-tests

# Report in eine Datei statt nach stdout schreiben
codecharter coverage --output-file coverage-report.json

Der JSON-Report geht nach stdout, Diagnosen und eine einzeilige Zusammenfassung nach stderr. Durch diese Trennung bleibt codecharter coverage > report.json in einer Pipeline direkt verwendbar, ohne dass Sie etwas herausfiltern müssen.

Optionen

Option Standard Beschreibung
[root] aktuelles Verzeichnis Verzeichnisbaum, der nach Testprojekten durchsucht wird.
--min-coverage <prozent> aus der Konfiguration Geforderte Mindest-Line-Coverage (0 bis 100). Überschreibt den konfigurierten Wert für diesen Lauf. Die Zahl wird gebietsschema-unabhängig gelesen, 99.5 ist also überall korrekt, 99,5 nicht.
--results-root <verzeichnis> <root>/TestResults/coverage Ablage für Test- und Coverage-Artefakte. Ein relativer Pfad wird gegen das aktuelle Arbeitsverzeichnis aufgelöst, nicht gegen root.
--skip-tests aus Tests nicht ausführen, sondern die bereits vorhandenen Coverage-Dateien unterhalb des Results-Root auswerten.
--output-file <pfad> stdout JSON-Report in diese Datei schreiben.
--verbose aus Zusätzlich informative Fortschrittszeilen nach stderr ausgeben.
--no-color aus ANSI-Farbcodes abschalten.

--skip-tests prüft vor der Auswertung, ob zu jedem gefundenen Testprojekt eine Coverage-Datei vorliegt. Ein veralteter oder abgebrochener Lauf kann das Gate so nicht unbemerkt passieren. Stammt das Ergebnisverzeichnis von einem anderen Werkzeug und trägt nicht die Ablage je Projekt, fällt die Prüfung auf einen Abgleich der Anzahlen zurück und weist darauf hin.

Konfiguration

Die Policy steht in .codecharter/config.yml, wird also einmal eingecheckt und gilt für alle:

coverage:
  minimum-percent: 99.5        # Schwelle des Gates (0 bis 100), Standard 100
  snippet-context-lines: 3     # Kontextzeilen um jede ungedeckte Region
  exclude:                     # von der Messung ausgenommene Dateien (Globs)
    - "**/*.Designer.cs"
    - "src/Generated/**"

Alle drei Schlüssel gelten repositoryweit. Anders als die Analyse-Sektionen lässt sich coverage nicht pro Pfad-Scope variieren. Globs werden groß-/kleinschreibungsgenau gegen Pfade relativ zum Lauf-Root abgeglichen, geschrieben mit Schrägstrichen (**/ überspannt Verzeichnisse, * bleibt innerhalb eines Pfadsegments).

Beachten Sie, dass coverage.exclude unabhängig vom übergeordneten exclude der Analyse ist. Ein von der Regelanalyse ausgenommener Ordner verschwindet also nicht stillschweigend aus Ihrer Coverage-Zahl, und umgekehrt.

Die wirksame Schwelle wird in dieser Reihenfolge bestimmt:

  1. --min-coverage auf der Kommandozeile
  2. .codecharter/config.local.yml (Ihr persönliches, maschinenlokales Overlay)
  3. .codecharter/config.yml (die eingecheckte Team-Einstellung)
  4. der eingebaute Standardwert 100

Der Report nennt, welche der vier Quellen gewonnen hat, sodass sich ein überraschendes Gate-Ergebnis immer zurückverfolgen lässt. Eine coverage.exclude-Liste im lokalen Overlay ersetzt dabei die eingecheckte Liste, sie ergänzt sie nicht.

All das lässt sich auch von der Kommandozeile aus pflegen statt von Hand, siehe codecharter config.

Was in die Zahl einfließt

Positional Records, die nur Daten tragen, enthalten kein Verhalten, das sich zu testen lohnt, und bleiben deshalb außerhalb der Messung. Ein Record gilt so lange als reiner Datenträger, wie kein Mitglied einen selbst geschriebenen Rumpf hat: Auto-Properties (auch mit init) und der generierte Primärkonstruktor erhalten diesen Status, während eine berechnete Property, ein prüfender Konstruktor, ein Methodenrumpf, ein Operator, ein Indexer oder ein Event den gesamten Record wieder in das Gate holen.

Klassen und Structs werden auf diesem Weg nie ausgenommen. Die Ausnahme ist bewusst auf Records beschränkt, weil nur ein Record den Vertrag "Daten, keine Logik" ausdrücklich erklärt.

Alles Weitere nehmen Sie selbst aus, über coverage.exclude.

Exit-Codes

Code Bedeutung
0 Die Coverage hat den geforderten Mindestwert erreicht.
1 Die Coverage liegt unter dem geforderten Mindestwert.
2 Tests sind fehlgeschlagen oder die Coverage-Daten waren unvollständig.
3 Überhaupt keine Coverage-Daten.
64 Fehler in Aufruf, Konfiguration oder Umgebung (etwa ein fehlendes .NET SDK oder ein nicht beschreibbares --output-file).

Das Gate ist fail-closed: fehlende, leere oder unlesbare Coverage-Daten führen nie zu einem Erfolg. Exit-Code 3 bedeutet "es wurde nichts gemessen" und erscheint niemals als grüne 100 %.

Die angezeigte Prozentzahl wird abgerundet. 100.00 % heißt also, dass jede messbare Zeile gedeckt ist, und sonst nichts. Eine einzige ungedeckte Zeile in einer großen Solution erscheint als 99.99 % und lässt ein Gate mit 100 % fehlschlagen, statt sich zu einem falschen Erfolg aufzurunden.

Der Report

Der JSON-Report besteht aus drei Teilen:

  • summary: messbare Zeilen, gedeckte Zeilen, der Prozentwert, der geforderte Mindestwert, dessen Herkunft, das Gate-Ergebnis und das Alter der ausgewerteten Coverage-Dateien.
  • testResults: ein Eintrag je Testprojekt mit dessen Exit-Code (leer, wenn Sie --skip-tests verwenden).
  • uncoveredRegions: jeder zusammenhängende Block nie ausgeführter Zeilen, mit Datei (als absoluter Pfad und relativ zum Lauf-Root), umgebender Methode, Zeilennummern und Quelltext-Ausschnitt.

Der relative Pfad ist der stabile Schlüssel für CI-Annotationen, denn er hängt nicht davon ab, wohin der Build-Agent das Repository ausgecheckt hat.

In der CI

- name: Coverage gate
  run: codecharter coverage --output-file coverage-report.json
  # Exit-Code 1 färbt den Schritt rot, sobald die Coverage unter den Mindestwert fällt.

Da die Schwelle in der Konfigurationsdatei steht, muss die Pipeline-Definition nicht angefasst werden, wenn das Team die Latte höher legt.

Mit einem KI-Assistenten

Dasselbe Gate steht KI-Coding-Assistenten als Tool run_coverage des MCP-Servers zur Verfügung. Der Assistent erhält die ungedeckten Regionen samt Datei, Methode, Zeilennummern und Ausschnitt, also alles, was er braucht, um die fehlenden Tests zu schreiben, ohne vorher danach zu suchen.

Weiterführend