Code Coverage via CLI

Einleitung

Eine gute Code Coverage-Übersicht hilft sehr dabei, Stellen im Code zu identifizieren, für die noch Unit Tests ergänzt werden sollten. In Visual Studio gibt es dafür im Menü Test unter Analyze Code Coverage for All Tests ein nützliches Fenster.

Dieses Fenster steht einem allerdings nur in der Enterprise Version von Visual Studio zur Verfügung.

Will man eine ähnliche Erfahrung haben, das aber möglichst ohne zusätzliche Kosten, muss man schon etwas wühlen, bis man eine Lösung findet.
Ich selbst fand mich in der Lage wieder, mit einer Professional-Version von Visual Studio zu arbeiten, bei der aus mir unbekannten Gründen Extensions wie Fine Code Coverage nicht zuverlässig funktionieren wollten.

Zu meiner Rettung stieß ich dann auf zwei CLI-Tools, die mir enorm weiterhelfen sollten: dotnet-coverage und dotnet-reportgenerator-globaltool.

Ein Beispiel inklusive des nötigen PowerShell-Scripts zur Verwendung der nachfolgend beschriebenen Lösung steht im GitHub-Repository der blecon GmbH zur Verfügung.

Einrichtung der Code Coverage

Um die beiden genannten Tools verwenden zu können, muss man sie zunächst einmalig installieren. Das ist über das .NET CLI sehr einfach gemacht:

dotnet tool install -global dotnet-coverage
dotnet tool install -global dotnet-reportgenerator-globaltool

Sammeln von Daten

Sind beide Tools installiert, kann man mit dem Sammeln der nötigen Daten für eine Code Coverage-Ansicht beginnen.

Führt man dotnet-coverage wie folgt aus, wird ein neuer Test-Run gestartet und das Tool legt die Coverage-Daten in der Datei coverage.xml ab.

dotnet-coverage collect --output-format xml --output coverage.xml dotnet test <solution/project>

Erstellen des Coverage-Reports

Man kann mit dem folgenden Befehl einen HTML-Bericht aus den Coverage-Daten erzeugen.

reportgenerator -reports:coverage.xml -targetdir:.\report

Das Tool erzeugt den Bericht, mit allen nötigen Dateien im Verzeichnis report. Man kann nun in diesem Verzeichnis index.html im Browser öffnen, wodurch man eine Seite wie die folgende sieht.

Wie im Visual Studio-Fenster kann man hier sehen, dass die Testabdeckung für CalculatorLibrary.Calculator bei mageren 25% liegt.

Drilldown im Coverage-Report

Der Report erlaubt es nun auch, sich in der Hierarchie nach unten zu bohren. Klicke ich zum Beispiel auf die Zeile CalculatorLibrary.Calculator, bekomme ich eine hübsche Übersicht über die (nicht) abgedeckten Code-Zeilen.

Das hilft mir definitiv weiter, wenn ich wissen will, welche Tests ich noch schreiben muss.

One step further

Böse Zungen behaupten ja immer wieder, dass Entwickler nur deswegen Entwickler geworden sind, weil sie faul sind. Und ja, was soll ich sagen, da ist doch auch was dran, oder?
Ich jedenfalls war zu faul, jedes Mal die beiden nötigen Befehle einzutippen, um einen aktuellen Coverage-Bericht zu bekommen. Darum habe ich für das hier verwendete Demo-Projekt eine PS1-Datei mit folgendem Inhalt zusammengebaut.

Remove-Item -Path ".\CodeCoverage" -Recurse -Force
dotnet-coverage collect --output-format xml --output .\CodeCoverage\coverage.xml dotnet test CodeCoverageDemo.sln
reportgenerator -reports:.\CodeCoverage\coverage.xml -targetdir:.\CodeCoverage\report

Im ersten Schritt lösche ich hier bisherige Code Coverage-Daten. Danach erzeuge ich die aktuellen Daten und erstelle schließlich den Bericht.
Jetzt brauche ich nur noch im Browser meine Seite neu zu laden und habe die aktuellen Code Coverage-Ergebnisse zur Hand.

Fazit

Zwar bietet mir diese Methode „nur“ eine Line Coverage, eine Method Coverage müsste gegen den Einwurf kleiner Münzen freigeschaltet werden. Aber ich bin der Meinung, das ist allemal deutlich besser als nichts.
Mir jedenfalls haben die so erzeugten Berichte in meinem aktuellen Kundenprojekt ziemlich weitergeholfen.

Ich hoffe, dass sie auch dem ein oder anderen da draußen zu Diensten sein werden.

0 Kommentare

Hinterlasse einen Kommentar

An der Diskussion beteiligen?
Hinterlasse uns deinen Kommentar!

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert