はじめに
今回はdotnet test
でコードカバレッジを収集する際にExcludeFromCodeCoverageAttribute
を用いて対象外にする設定をする方法を紹介したいと思います。
learn.microsoft.com
コードカバレッジ収集について
コードカバレッジ収集はcoverlet.collector
を利用している前提で話をすすめていきます。
https://www.nuget.org/packages/coverlet.collector
$ dotnet add package coverlet.collector
# 必須 : --collect:"XPlat Code Coverage" # 任意: --results-directoryにより出力先フォルダを指定できる。出力先ディレクトリ/<GUID>/coverage.cobertura.xmlのように出力され、GUIDは必ずついてくる $ dotnet test --collect:"XPlat Code Coverage"--results-directory:"./Result" Determining projects to restore... 復元対象のすべてのプロジェクトは最新です。 // ...テスト実行を開始しています。お待ちください...合計 1個のテスト ファイルが指定されたパターンと一致しました。 成功!-失敗: 0、合格: 3、スキップ: 0、合計: 3、期間: 13 ms - TestProject1.dll (net8.0)添付ファイル: <ProjectRoot>/Result/bb585210-e6ba-45a6-a15f-4d86d782b69a/coverage.cobertura.xml
詳細については以下の記事で触れているので、利用方法が不明な方は参照してみてください。
www.hanachiru-blog.com
コードカバレッジの収集対象外に設定する
対象外にしたいクラスまたは構造体に対して[ExcludeFromCodeCoverage]
を付与してあげます。
using System.Diagnostics.CodeAnalysis; [ExcludeFromCodeCoverage] publicclassProgram { publicstaticvoid Main() { Console.WriteLine("Hello World!"); } }
クラスまたは構造体にこの属性を配置すると、そのクラスまたは構造体のすべてのメンバーがコード カバレッジ情報のコレクションから除外されます。
ExcludeFromCodeCoverageAttribute クラス (System.Diagnostics.CodeAnalysis) | Microsoft Learn
また実装をみてみると、公式ドキュメントには記述がありませんでしたがクラス・構造体以外にも以下に対応していそうでした。
Assembly
Class
Struct
Constructor
Method
Property
Event
namespace System.Diagnostics.CodeAnalysis { [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Constructor | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Event, Inherited =false, AllowMultiple =false)] publicsealedclassExcludeFromCodeCoverageAttribute : Attribute { public ExcludeFromCodeCoverageAttribute() { } /// <summary>Gets or sets the justification for excluding the member from code coverage.</summary>publicstring? Justification { get; set; } } }
実験
実際にclass
に対して付与してみて、コードカバレッジの変化を見てみます。
$ tree . ├── Program.cs ├── SampleHelper.cs ├── SampleConsoleNet8.csproj
using System.Diagnostics.CodeAnalysis; [ExcludeFromCodeCoverage] publicclassProgram { publicstaticvoid Main() { Console.WriteLine("Hello World!"); } }
namespace SampleConsoleNet8; publicstaticclassSampleHelper { publicstaticstring GetSampleString() { return"Sample String"; } publicstaticstring GetSampleString2(string text) { if (string.IsNullOrEmpty(text)) { return""; } return$"Sample String: {text}"; } }
coberturaの変化
やや分かりづらいですが、Program
に関する記述がまるっとなくなっています。
ExcludeFromCodeCoverageAttribute
を付与しない場合
<?xml version="1.0" encoding="utf-8"?><coverage line-rate="0.6666"branch-rate="0.5"version="1.9"timestamp="1729422662"lines-covered="8"lines-valid="12"branches-covered="1"branches-valid="2"><sources><source>----/SampleConsoleNet8/</source></sources><packages><package name="SampleConsoleNet8"line-rate="0.6666"branch-rate="0.5"complexity="4"><classes><class name="Program"filename="Program.cs"line-rate="0"branch-rate="1"complexity="1"><methods><method name="Main"signature="()"line-rate="0"branch-rate="1"complexity="1"><!-- 省略 --></methods><lines><!-- 省略 --></lines></class><class name="SampleConsoleNet8.SampleHelper"filename="SampleHelper.cs"line-rate="0.8887999999999999"branch-rate="0.5"complexity="3"><methods><!-- 省略 --></method></methods><lines><!-- 省略 --></lines></class></classes></package></packages></coverage>
ExcludeFromCodeCoverageAttribute
付与した場合
<?xml version="1.0" encoding="utf-8"?><coverage line-rate="0.8887999999999999"branch-rate="0.5"version="1.9"timestamp="1729422682"lines-covered="8"lines-valid="9"branches-covered="1"branches-valid="2"><sources><source>/</source></sources><packages><package name="SampleConsoleNet8"line-rate="0.8887999999999999"branch-rate="0.5"complexity="3"><classes><class name="SampleConsoleNet8.SampleHelper"filename="----/SampleHelper.cs"line-rate="0.8887999999999999"branch-rate="0.5"complexity="3"><methods><!-- 省略 --></methods><lines><!-- 省略 --></lines></class></classes></package></packages></coverage>