コード カバレッジ分析のカスタマイズ
既定では、コード カバレッジは、単体テスト中に読み込まれるすべてのソリューション アセンブリを分析します。 多くの場合は、この設定が効果的なので、この既定のビヘイビアーを使用することをお勧めします。 詳細については、「コード カバレッジを使用した、テストされるコード割合の確認」を参照してください。
テスト コードをコード カバレッジの結果から除外して、アプリケーション コードのみを含めるには、ExcludeFromCodeCoverageAttribute 属性をテスト クラスに追加します。
ソリューションの一部ではないアセンブリを含めるには、これらのアセンブリの .pdb ファイルを取得し、アセンブリの .dll ファイルと同じフォルダーにコピーします。
注
コード カバレッジは、Visual Studio Enterprise でのみ使用できます。 .NET コード カバレッジには、代わりにコマンド ライン ツール dotnet-coverageを使用できます。
実行設定ファイル
実行設定ファイルは、単体テスト ツールによって使用される構成ファイルです。 詳細なコード カバレッジの設定は、.runsettings ファイルで指定されます。
コード カバレッジをカスタマイズするには、次の手順に従います。
実行設定ファイルをソリューションに追加します。 ソリューション エクスプローラーでソリューションのショートカット メニューを開き、[追加]>[新しい項目]、[XML ファイル] の順に選択します。 CodeCoverage.runsettings などの名前でファイルを保存します。
すべての項目テンプレートが表示されない場合は、[テンプレートをすべて表示] を選択してから、項目テンプレートを選びます。
この記事の最後にあるファイル例の内容を追加し、後続の各セクションの説明どおりに、ニーズに合わせてカスタマイズします。
実行設定ファイルを選びます。
Visual Studio 2019 バージョン 16.4 以降では、プロジェクト ルートで実行設定ファイルを自動検出できます。 それ以外の場合は、[テスト] メニューの [実行設定の構成] を選び、次に [ソリューション全体の runsettings ファイルの選択] を選びます。 テストの実行で使用する実行設定ファイルをコマンド ラインから指定するには、単体テストの構成に関する記事を参照してください。
コード カバレッジを分析するを選択すると、構成情報が実行設定ファイルから読み取られます。
ヒント
前のコード カバレッジの結果とコードの色分けは、テストを実行したりコードを更新したりしても、自動的に非表示にはなりません。
カスタム設定のオンとオフを切り替えるには、[テスト] メニューで、ファイルを選択したり選択解除したりします。
実行設定ファイルを選択するには、[テスト] メニューで [設定ファイルの選択] を選びます。 テストの実行で使用する実行設定ファイルをコマンド ラインから指定するには、単体テストの構成に関する記事を参照してください。
コード カバレッジを分析するを選択すると、構成情報が実行設定ファイルから読み取られます。
ヒント
前のコード カバレッジの結果とコードの色分けは、テストを実行したりコードを更新したりしても、自動的に非表示にはなりません。
カスタム設定をオフまたはオンにするには、[テスト ]、[実行設定の構成] を選択し、ファイル名を選択または選択解除してください。
シンボルの検索パス
コード カバレッジには、アセンブリのシンボル ファイル (.pdb ファイル) が必要です。 ソリューションによってビルドされたアセンブリの場合は通常、シンボル ファイルがバイナリ ファイルとともに存在していて、コード カバレッジは自動的に動作します。 場合によっては、参照されるアセンブリをコード カバレッジ分析に追加したいこともあります。 その場合は、.pdb ファイルがバイナリの近くにないこともありますが、シンボル検索パスを .runsettings ファイルで指定できます。
<SymbolSearchPaths>
<Path>\\mybuildshare\builds\ProjectX</Path>
<!--More paths if required-->
</SymbolSearchPaths>
注
シンボルの解決には、多数のアセンブリでリモートのファイルの場所を使用しているときは特に、時間がかかる可能性があります。 そのため、.pdb ファイルをバイナリ (.dll および .exe) ファイルと同じローカルの場所にコピーすることを検討してください。
アセンブリやメンバーを含めるか除外する
アセンブリまたは特定の型とメンバーをコード カバレッジ分析に含めたり、コード カバレッジ分析から除外したりできます。 [含める] セクションが空か省略されている場合、読み込まれ、PDB ファイルが関連付けられているアセンブリがすべて含まれます。 アセンブリまたはメンバーが [除外する] セクションの句に一致する場合、それはコード カバレッジから除外されます。 [除外する] セクションは [含める] セクションに優先します。あるアセンブリが [含める] と [除外する] の両方に記載されている場合、コード カバレッジには含まれません。
たとえば、次の XML では、その名前を指定することで 1 つのアセンブリが除外されます。
<ModulePaths>
<Exclude>
<ModulePath>.*Fabrikam.Math.UnitTest.dll</ModulePath>
<!-- Add more ModulePath nodes here. -->
</Exclude>
</ModulePaths>
次の例では、アセンブリを 1 つだけコード カバレッジに含めると指定されます。
<ModulePaths>
<Include>
<ModulePath>.*Fabrikam.Math.dll</ModulePath>
<!-- Add more ModulePath nodes here. -->
</Include>
</ModulePaths>
次の表では、コード カバレッジに含めるか、コード カバレッジから除外する目的でアセンブリやメンバーを照合するさまざまな方法をまとめています。
XML 要素 | 一致する項目 |
---|---|
ModulePath | アセンブリ名またはファイル パスで指定されたアセンブリと一致します。 |
CompanyName | Company 属性でアセンブリと一致します。 |
PublicKeyToken | 公開キー トークンで署名付きアセンブリと一致します。 |
Source | 要素が定義されているソース ファイルのパス名で要素と一致します。 |
Attribute | 指定された属性を持つ要素と一致します。 <Attribute>^System\.Diagnostics\.DebuggerHiddenAttribute$</Attribute> などの、属性の完全な名前を指定します。CompilerGeneratedAttribute 属性を除外すると、 async 、await 、yield return などの言語機能を使用するコードと、自動実装プロパティがコード カバレッジ分析から除外されます。 真に生成されたコードを除外するには、GeneratedCodeAttribute 属性のみを除外します。 |
Function | パラメーター リストなど、完全修飾名でプロシージャ、関数、またはメソッドと一致します。 正規表現を利用し、名前の一部を照合することもできます。 例: Fabrikam.Math.LocalMath.SquareRoot(double); (C#)Fabrikam::Math::LocalMath::SquareRoot(double) (C++) |
コード カバレッジの形式
既定では、コード カバレッジは収集されて、.coverage
ファイルに保存されます。 XMLやCoberturaなどの他の形式を使用してカバレッジを収集することもできます。 異なる形式は、さまざまなエディターやパイプラインで役立つ場合があります。 これは runsettings で有効にできます。その場合、runsettings ファイルの DataCollector 構成セクションで <Format>Cobertura</Format>
または <Format>Xml</Format>
を追加します。 この形式は、Visual Studio Enterprise の [コード カバレッジの結果] ウィンドウで表示できます。
また、runsettings ファイルで指定するか、パラメーターで指定することで、コマンド ラインから異なる形式を指定することもできます。 たとえば、dotnet コマンド ラインでは dotnet test --collect:"Code Coverage;Format=Cobertura"
を使用します。 vstest の場合、vstest.console.exe /collect:"Code Coverage;Format=Cobertura"
を使用します。 collect パラメーターは、runsettings で指定された形式をオーバーライドします。
静的および動的ネイティブ インストルメンテーション
Visual Studio 2022 バージョン 17.2 では、ネイティブ バイナリを静的に (ディスク上に) インストルメント化するオプションを追加しました。 以前のバージョンでは、メソッドをインストルメント化できない動的インストルメンテーションのみがサポートされていました。 静的ネイティブ インストルメンテーションの方が安定しており、推奨されています。 静的ネイティブ インストルメンテーションについては、コード カバレッジの収集が必要なすべてのネイティブ プロジェクトに対して /PROFILE リンク オプションを有効にすることが必要です。
runsettings で <CodeCoverage>
タグの下に <EnableStaticNativeInstrumentation>True</EnableStaticNativeInstrumentation>
を追加することでも、静的ネイティブ インストルメンテーションを有効にできます。 コマンド ライン シナリオでは、このメソッドを使用します。
既定では、動的ネイティブ インストルメンテーションは常に有効になっています。 静的インストルメンテーションと動的インストルメンテーションの両方が有効になっている場合、Visual Studio によって、C++ コードの静的インストルメント化が試行されますが、これが不可能な場合 (/PROFILE
リンク オプションが有効になっていない場合など)、動的インストルメンテーションが使用されます。 runsettings での動的ネイティブ インストルメンテーションを完全に無効にするには、<CodeCoverage>
の下に <EnableDynamicNativeInstrumentation>False</EnableDynamicNativeInstrumentation>
を追加します。
静的ネイティブ インストルメンテーションが有効になっている場合は、テスト実行の前にネイティブ バイナリがインストルメント化され、ディスクで置き換えられます。 テストの実行後、元のバイナリが復元されます。 runsettings で元のファイルの復元を無効にするには、<CodeCoverage>
タグの下に <EnableStaticNativeInstrumentationRestore>False</EnableStaticNativeInstrumentationRestore>
を追加します。 これは、CI シナリオで特に役立ちます。
静的ネイティブ インストルメンテーションが有効になっている場合は、テスト バイナリが配置されているディレクトリ内のすべてのネイティブ バイナリが、Visual Studio によって検索およびインストルメント化されます。 バイナリを検索する必要がある追加のディレクトリを指定できます。 次の例では、末尾が Fabrikam.Math.dll
のファイルを除き、C:\temp
とそのサブディレクトリからのすべてのネイティブ バイナリがインストルメント化される必要があるように指定します。
<ModulePaths>
<IncludeDirectories>
<Directory Recursive="true">C:\temp</Directory>
</IncludeDirectories>
<Exclude>
<ModulePath>.*Fabrikam.Math.dll</ModulePath>
</Exclude>
</ModulePaths>
正規表現
Include ノードと Exclude ノードが使用する正規表現は、ワイルドカードと同じではありません。 すべての照合で、大文字と小文字が区別されません。 次に、例をいくつか示します。
.* は任意の文字の文字列と一致します
\. はピリオド "." と一致します
\( \) は丸括弧 "( )" に一致します
\\ はファイル パス区切り記号 "\" と照合します
^ は文字列の先頭と一致します
$ は文字列の末尾と照合します
次の XML は、正規表現を使用して、特定のアセンブリを含める方法と除外する方法を示しています。
<ModulePaths>
<Include>
<!-- Include all loaded .dll assemblies (but not .exe assemblies): -->
<ModulePath>.*\.dll$</ModulePath>
</Include>
<Exclude>
<!-- But exclude some assemblies: -->
<ModulePath>.*\\Fabrikam\.MyTests1\.dll$</ModulePath>
<!-- Exclude all file paths that contain "Temp": -->
<ModulePath>.*Temp.*</ModulePath>
</Exclude>
</ModulePaths>
次の XML は、正規表現を使用して、特定の関数を含める方法と除外する方法を示しています。
<Functions>
<Include>
<!-- Include methods in the Fabrikam namespace: -->
<Function>^Fabrikam\..*</Function>
<!-- Include all methods named EqualTo: -->
<Function>.*\.EqualTo\(.*</Function>
</Include>
<Exclude>
<!-- Exclude methods in a class or namespace named UnitTest: -->
<Function>.*\.UnitTest\..*</Function>
</Exclude>
</Functions>
警告
正規表現にエラー (エスケープされていないか、対応していないかっこなど) があると、コード カバレッジ分析は実行されません。
正規表現の詳細については、「Visual Studio での正規表現の使用」を参照してください。
サンプルの .runsettings ファイル
このコードをコピーし、自分のニーズに合わせて編集してください。
<?xml version="1.0" encoding="utf-8"?>
<!-- File name extension must be .runsettings -->
<RunSettings>
<DataCollectionRunSettings>
<DataCollectors>
<DataCollector friendlyName="Code Coverage" uri="datacollector://Microsoft/CodeCoverage/2.0" assemblyQualifiedName="Microsoft.VisualStudio.Coverage.DynamicCoverageDataCollector, Microsoft.VisualStudio.TraceCollector, Version=11.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<Configuration>
<CodeCoverage>
<Format>coverage</Format>
<!--
Additional paths to search for .pdb (symbol) files. Symbols must be found for modules to be instrumented.
If .pdb files are in the same folder as the .dll or .exe files, they are automatically found. Otherwise, specify them here.
Note that searching for symbols increases code coverage runtime. So keep this small and local.
-->
<!--
<SymbolSearchPaths>
<Path>C:\Users\username\source\repos\ProjectX</Path>
<Path>\\mybuildshare\builds\ProjectX</Path>
</SymbolSearchPaths>
-->
<!--
About include/exclude lists:
Empty "Include" clauses imply all; empty "Exclude" clauses imply none.
Each element in the list is a regular expression (ECMAScript syntax). See /visualstudio/ide/using-regular-expressions-in-visual-studio.
An item must first match at least one entry in the include list to be included.
Included items must then not match any entries in the exclude list to remain included.
-->
<!-- Match assembly file paths: -->
<ModulePaths>
<Include>
<ModulePath>.*\.dll$</ModulePath>
<ModulePath>.*\.exe$</ModulePath>
</Include>
<Exclude>
<ModulePath>.*CPPUnitTestFramework.*</ModulePath>
</Exclude>
<!-- Specifies additional list of directories where binaries static native instrumentation should be searched. -->
<IncludeDirectories>
<Directory Recursive="true">C:\b59fb11c-1611-4562-9a2b-c35719da65d3</Directory>
</IncludeDirectories>
</ModulePaths>
<!-- Match fully qualified names of functions: -->
<!-- (Use "\." to delimit namespaces in C# or Visual Basic, "::" in C++.) -->
<Functions>
<Exclude>
<Function>^Fabrikam\.UnitTest\..*</Function>
<Function>^std::.*</Function>
<Function>^ATL::.*</Function>
<Function>.*::__GetTestMethodInfo.*</Function>
<Function>^Microsoft::VisualStudio::CppCodeCoverageFramework::.*</Function>
<Function>^Microsoft::VisualStudio::CppUnitTestFramework::.*</Function>
</Exclude>
</Functions>
<!-- Match attributes on any code element: -->
<Attributes>
<Exclude>
<!-- Don't forget "Attribute" at the end of the name -->
<Attribute>^System\.Diagnostics\.DebuggerHiddenAttribute$</Attribute>
<Attribute>^System\.Diagnostics\.DebuggerNonUserCodeAttribute$</Attribute>
<Attribute>^System\.CodeDom\.Compiler\.GeneratedCodeAttribute$</Attribute>
<Attribute>^System\.Diagnostics\.CodeAnalysis\.ExcludeFromCodeCoverageAttribute$</Attribute>
</Exclude>
</Attributes>
<!-- Match the path of the source files in which each method is defined: -->
<Sources>
<Exclude>
<Source>.*\\atlmfc\\.*</Source>
<Source>.*\\vctools\\.*</Source>
<Source>.*\\public\\sdk\\.*</Source>
<Source>.*\\microsoft sdks\\.*</Source>
<Source>.*\\vc\\include\\.*</Source>
</Exclude>
</Sources>
<!-- Match the company name property in the assembly: -->
<CompanyNames>
<Exclude>
<CompanyName>.*microsoft.*</CompanyName>
</Exclude>
</CompanyNames>
<!-- Match the public key token of a signed assembly: -->
<PublicKeyTokens>
<!-- Exclude Visual Studio extensions: -->
<Exclude>
<PublicKeyToken>^B77A5C561934E089$</PublicKeyToken>
<PublicKeyToken>^B03F5F7F11D50A3A$</PublicKeyToken>
<PublicKeyToken>^31BF3856AD364E35$</PublicKeyToken>
<PublicKeyToken>^89845DCD8080CC91$</PublicKeyToken>
<PublicKeyToken>^71E9BCE111E9429C$</PublicKeyToken>
<PublicKeyToken>^8F50407C4E9E73B6$</PublicKeyToken>
<PublicKeyToken>^E361AF139669C375$</PublicKeyToken>
</Exclude>
</PublicKeyTokens>
<!-- We recommend you do not change the following values: -->
<!-- Set this to True to collect coverage information for functions marked with the "SecuritySafeCritical" attribute. Instead of writing directly into a memory location from such functions, code coverage inserts a probe that redirects to another function, which in turns writes into memory. -->
<UseVerifiableInstrumentation>True</UseVerifiableInstrumentation>
<!-- When set to True, collects coverage information from child processes that are launched with low-level ACLs, for example, UWP apps. -->
<AllowLowIntegrityProcesses>True</AllowLowIntegrityProcesses>
<!-- When set to True, collects coverage information from child processes that are launched by test or production code. -->
<CollectFromChildProcesses>True</CollectFromChildProcesses>
<!-- When set to True, restarts the IIS process and collects coverage information from it. -->
<CollectAspDotNet>False</CollectAspDotNet>
<!-- When set to True, static native instrumentation will be enabled. -->
<EnableStaticNativeInstrumentation>True</EnableStaticNativeInstrumentation>
<!-- When set to True, dynamic native instrumentation will be enabled. -->
<EnableDynamicNativeInstrumentation>True</EnableDynamicNativeInstrumentation>
<!-- When set to True, instrumented binaries on disk are removed and original files are restored. -->
<EnableStaticNativeInstrumentationRestore>True</EnableStaticNativeInstrumentationRestore>
</CodeCoverage>
</Configuration>
</DataCollector>
</DataCollectors>
</DataCollectionRunSettings>
</RunSettings>
<?xml version="1.0" encoding="utf-8"?>
<!-- File name extension must be .runsettings -->
<RunSettings>
<DataCollectionRunSettings>
<DataCollectors>
<DataCollector friendlyName="Code Coverage" uri="datacollector://Microsoft/CodeCoverage/2.0" assemblyQualifiedName="Microsoft.VisualStudio.Coverage.DynamicCoverageDataCollector, Microsoft.VisualStudio.TraceCollector, Version=11.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<Configuration>
<CodeCoverage>
<!--
Additional paths to search for .pdb (symbol) files. Symbols must be found for modules to be instrumented.
If .pdb files are in the same folder as the .dll or .exe files, they are automatically found. Otherwise, specify them here.
Note that searching for symbols increases code coverage runtime. So keep this small and local.
-->
<!--
<SymbolSearchPaths>
<Path>C:\Users\username\source\repos\ProjectX</Path>
<Path>\\mybuildshare\builds\ProjectX</Path>
</SymbolSearchPaths>
-->
<!--
About include/exclude lists:
Empty "Include" clauses imply all; empty "Exclude" clauses imply none.
Each element in the list is a regular expression (ECMAScript syntax). See /visualstudio/ide/using-regular-expressions-in-visual-studio.
An item must first match at least one entry in the include list to be included.
Included items must then not match any entries in the exclude list to remain included.
-->
<!-- Match assembly file paths: -->
<ModulePaths>
<Include>
<ModulePath>.*\.dll$</ModulePath>
<ModulePath>.*\.exe$</ModulePath>
</Include>
<Exclude>
<ModulePath>.*CPPUnitTestFramework.*</ModulePath>
</Exclude>
<!-- Specifies additional list of directories where binaries static native instrumentation should be searched. -->
<IncludeDirectories>
<Directory Recursive="true">C:\b59fb11c-1611-4562-9a2b-c35719da65d3</Directory>
</IncludeDirectories>
</ModulePaths>
<!-- Match fully qualified names of functions: -->
<!-- (Use "\." to delimit namespaces in C# or Visual Basic, "::" in C++.) -->
<Functions>
<Exclude>
<Function>^Fabrikam\.UnitTest\..*</Function>
<Function>^std::.*</Function>
<Function>^ATL::.*</Function>
<Function>.*::__GetTestMethodInfo.*</Function>
<Function>^Microsoft::VisualStudio::CppCodeCoverageFramework::.*</Function>
<Function>^Microsoft::VisualStudio::CppUnitTestFramework::.*</Function>
</Exclude>
</Functions>
<!-- Match attributes on any code element: -->
<Attributes>
<Exclude>
<!-- Don't forget "Attribute" at the end of the name -->
<Attribute>^System\.Diagnostics\.DebuggerHiddenAttribute$</Attribute>
<Attribute>^System\.Diagnostics\.DebuggerNonUserCodeAttribute$</Attribute>
<Attribute>^System\.CodeDom\.Compiler\.GeneratedCodeAttribute$</Attribute>
<Attribute>^System\.Diagnostics\.CodeAnalysis\.ExcludeFromCodeCoverageAttribute$</Attribute>
</Exclude>
</Attributes>
<!-- Match the path of the source files in which each method is defined: -->
<Sources>
<Exclude>
<Source>.*\\atlmfc\\.*</Source>
<Source>.*\\vctools\\.*</Source>
<Source>.*\\public\\sdk\\.*</Source>
<Source>.*\\microsoft sdks\\.*</Source>
<Source>.*\\vc\\include\\.*</Source>
</Exclude>
</Sources>
<!-- Match the company name property in the assembly: -->
<CompanyNames>
<Exclude>
<CompanyName>.*microsoft.*</CompanyName>
</Exclude>
</CompanyNames>
<!-- Match the public key token of a signed assembly: -->
<PublicKeyTokens>
<!-- Exclude Visual Studio extensions: -->
<Exclude>
<PublicKeyToken>^B77A5C561934E089$</PublicKeyToken>
<PublicKeyToken>^B03F5F7F11D50A3A$</PublicKeyToken>
<PublicKeyToken>^31BF3856AD364E35$</PublicKeyToken>
<PublicKeyToken>^89845DCD8080CC91$</PublicKeyToken>
<PublicKeyToken>^71E9BCE111E9429C$</PublicKeyToken>
<PublicKeyToken>^8F50407C4E9E73B6$</PublicKeyToken>
<PublicKeyToken>^E361AF139669C375$</PublicKeyToken>
</Exclude>
</PublicKeyTokens>
<!-- We recommend you do not change the following values: -->
<!-- Set this to True to collect coverage information for functions marked with the "SecuritySafeCritical" attribute. Instead of writing directly into a memory location from such functions, code coverage inserts a probe that redirects to another function, which in turns writes into memory. -->
<UseVerifiableInstrumentation>True</UseVerifiableInstrumentation>
<!-- When set to True, collects coverage information from child processes that are launched with low-level ACLs, for example, UWP apps. -->
<AllowLowIntegrityProcesses>True</AllowLowIntegrityProcesses>
<!-- When set to True, collects coverage information from child processes that are launched by test or production code. -->
<CollectFromChildProcesses>True</CollectFromChildProcesses>
<!-- When set to True, restarts the IIS process and collects coverage information from it. -->
<CollectAspDotNet>False</CollectAspDotNet>
</CodeCoverage>
</Configuration>
</DataCollector>
</DataCollectors>
</DataCollectionRunSettings>
</RunSettings>