.NET でコードカバレッジを収集&レポートする
.NET6 を使ったアプリの開発中にコードカバレッジの収集とレポートを出力しようとしたのですが、地味に情報がまとまっていなかったので残しておこうと思います。
なお、コードカバレッジにはcoverlet.collector
、レポート出力にはReportGenerator
を使用します。
coverlet.collector
はxUnit.NET
が規定で統合しているため、選択肢として挙がりやすいと思います。
開発環境
- Visual Studio 2022
- .NET 6.0.300
- coverlet.collector 3.1.2
- ReportGenerator 5.1.9
使用するソリューション
今回使用するソリューションはシンプルにコンソールアプリとしています。
Coverlet.Sample
プロジェクトに実装コードが含まれていて、Coverlet.Sample.Tests
にテストコードを実装するような構成です。
テストするのは次のようなCalculator
クラスとします。
public class Calculator { public int Add(int x, int y) => x + y; public int Subtract(int x, int y) => x - y; }
ReportGenerator をインストールする
基本的に以下の Microsoft Docs を読めばいいんですが、地味に間違っているのがReportGenerator
のインストールコマンドです。
ドキュメントには次のコマンドが記載されていますが、私のローカル環境で実行したところ失敗しました。
dotnet tool install -g dotnet-reportgenerator-globaltool
こんなメッセージが出力されます。 PS C:\Users\user> dotnet tool install -g dotnet-reportgenerator-globaltool
C:\Users\user\AppData\Local\Temp\xwqllpoi.5zb\restore.csproj : error NU1301: ソース https://pkgs.dev.azure.com/iyemon018/ _packaging/All-Packages/nuget/v3/index.json のサービス インデックスを読み込めません。 ツール パッケージを復元できませんでした。 ツール 'dotnet-reportgenerator-globaltool' をインストールできませんでした。この失敗は次の原因で生じた可能性があります。 * プレビュー リリースをインストールしようとしており、--version オプションを使用してバージョンを指定しなかった。 * この名前のパッケージが見つかったが、.NET ツールではなかった。 * 恐らくインターネットの接続の問題で、必須の NuGet フィードにアクセスできない。 * ツールの名前の誤入力。 パッケージの名前付けの強制を含む他の理由については、https://aka.ms/failure-installing-tool にアクセスしてください
実際にはこちらのページに記載されているコマンドを実行します。
次のコマンドであれば成功すると思います。
dotnet tool install --global dotnet-reportgenerator-globaltool --version 5.1.9
テストを実行する
xUnit.NET
+ coverlet.collect
でテストを実行するだけであれば次のコマンドを実行するだけで問題ありません。
dotnet test --collect:"XPlat Code Coverage"
ただし、出力される XML ファイルをレポートツールに食わせて出力する場合、フォーマットを指定する必要があります。
フォーマットのオプションはcoverlet.collection
のプロジェクトに記載されています。
フォーマットのデフォルトはcobertura
になっているので、今回のケースでは使用しなくてもいいのですが覚えておくと応用が効きます。
cobertura
のフォーマットで実行する場合は次のコマンドを実行します。
dotnet test --collect:"XPlat Code Coverage" -- DataCollectionRunSettings.DataCollectors.DataCollector.Configuration.Format=cobertura
データ収集構成を設定ファイルで定義する
コマンドでフォーマットを指定することも可能なのですが、coverlet.collect
ではそれ以外にもデータ収集構成を設定することが出来ます。
このデータ収集構成は XML ファイルとして定義でき、実行時に指定することが出来ます。
チームで開発する場合は、このデータ収集構成の設定ファイルを Git に保存しておけば、どの環境でも同一のレポートを出力することが出来ますし、CI を使って出力する際にも使用できます。
データ収集構成は次のような構成になっています。具体的なそれぞれの項目の意味は、上記のcoverlet.collection
プロジェクトページを参照してください。
<?xml version="1.0" encoding="utf-8" ?> <RunSettings> <DataCollectionRunSettings> <DataCollectors> <DataCollector friendlyName="XPlat code coverage"> <Configuration> <Format>json,cobertura,lcov,teamcity,opencover</Format> <Exclude>[coverlet.*.tests?]*,[*]Coverlet.Core*</Exclude> <!-- [Assembly-Filter]Type-Filter --> <Include>[coverlet.*]*,[*]Coverlet.Core*</Include> <!-- [Assembly-Filter]Type-Filter --> <ExcludeByAttribute>Obsolete,GeneratedCodeAttribute,CompilerGeneratedAttribute</ExcludeByAttribute> <ExcludeByFile>**/dir1/class1.cs,**/dir2/*.cs,**/dir3/**/*.cs,</ExcludeByFile> <!-- Globbing filter --> <IncludeDirectory>../dir1/,../dir2/,</IncludeDirectory> <SingleHit>false</SingleHit> <UseSourceLink>true</UseSourceLink> <IncludeTestAssembly>true</IncludeTestAssembly> <SkipAutoProps>true</SkipAutoProps> <DeterministicReport>false</DeterministicReport> </Configuration> </DataCollector> </DataCollectors> </DataCollectionRunSettings> </RunSettings>
-- DataCollectionRunSettings.DataCollectors.DataCollector.Configuration.Format=cobertura
と同じ構成にする場合は次のようにすればOKです。
<?xml version="1.0" encoding="utf-8" ?> <RunSettings> <DataCollectionRunSettings> <DataCollectors> <DataCollector friendlyName="XPlat code coverage"> <Configuration> <Format>cobertura</Format> </Configuration> </DataCollector> </DataCollectors> </DataCollectionRunSettings> </RunSettings>
あとは次のコマンドを実行すれば設定ファイルを使用してテストの実行とコードカバレッジの収集を実行してくれます。
dotnet test --collect:"XPlat Code Coverage" --settings coverlet.collect.runsettings
レポートを出力する
テストとコードカバレッジ収集を実行すると、テストプロジェクトのフォルダ配下にTestResults
フォルダが作成され、その配下にcoverage.cobertura.xml
ファイルが生成されます。
このファイルを使用して以下のコマンドを実行するとレポートが出力されます。
reportgenerator -reports:"Coverlet.Sample.Tests\TestResults\{guid}\coverage.cobertura.xml" -targetdir:"coveragereport" -reporttypes:Html
レポートはこんな感じで出力されます。
スクリプトで実行できるようにする
コマンドラインで毎回実行するのは時間の無駄なのでテスト実行+コードカバレッジ収集+レポート出力をPowerShell
で実行できるようにします。
今回のソリューションでは次のようにしました。
$runSettings = ".\runsettings.xml" $resultDirectory = ".\.TestResults" $reportsDirectory = ".\.TestReports" if (Test-Path $resultDirectory) { Remove-Item $resultDirectory -Recurse } if (Test-Path $reportsDirectory) { Remove-Item $reportsDirectory -Recurse } dotnet test .\Coverlet.Sample.Tests\Coverlet.Sample.Tests.csproj --collect:"XPlat Code Coverage" --results-directory $resultDirectory --settings $runSettings $xmlFileName = (Get-ChildItem $resultDirectory -Filter *.xml -Recurse -File)[0].FullName reportgenerator -reports:$xmlFileName -targetdir:$reportsDirectory -reporttypes:Html
設定ファイルはrunsettings.xml
に保存しておき、コードカバレッジは.TestResults
フォルダに出力します。
coverlet.collect
はカバレッジ結果の出力フォルダを GUID で生成するため、固定のフォルダ名にすることが出来ません。
仕方ないのでGet-ChildItem
でフルパスを取得するようにしています。
コードカバレッジの収集とレポート出力はあまりキャッチアップしないせいか気がつくと過去のプロジェクトでは使用できなくなっていたりします。 .NET の場合は LTS が GA されたタイミングで定期的に見直していくのが良さそうですね。