自定義程式代碼涵蓋範圍分析
根據預設,程式代碼涵蓋範圍會分析單元測試期間載入的所有解決方案元件。 建議您使用此預設行為,因為它大部分時間都正常運作。 如需詳細資訊,請參閱 使用程式碼涵蓋範圍來判斷程式碼測試了多少。
若要從程式代碼涵蓋範圍結果中排除測試程序代碼,並只包含應用程式程式代碼,請將 ExcludeFromCodeCoverageAttribute 屬性新增至您的測試類別。
若要包含不屬於您解決方案的元件,請取得這些元件的 .pdb 檔案,並將其複製到與元件 .dll 檔案相同的資料夾中。
執行配置檔案
執行設定檔 是單元測試工具所使用的組態檔。 進階程式代碼涵蓋範圍設定是在 .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) 檔案相同的本機位置。
包含或排除元件和成員
您可以從程式代碼涵蓋範圍分析中包含或排除元件或特定類型和成員。 如果 Include 區段是空的或省略的,則會包含所有已載入且具有相關 PDB 檔案的元件。 如果元件或成員符合 Exclude 區段中的 子句,則會從程式代碼涵蓋範圍中排除該子句。 Exclude 區段的優先順序高於 Include 區段:如果元件同時列在 Include 和 Exclude中,則不會包含在程式代碼涵蓋範圍中。
例如,下列 XML 會藉由指定其名稱來排除單一元件:
<ModulePaths>
<Exclude>
<ModulePath>.*Fabrikam.Math.UnitTest.dll</ModulePath>
<!-- Add more ModulePath nodes here. -->
</Exclude>
</ModulePaths>
下列範例會指定只有單一元件應該包含在程式代碼涵蓋範圍中:
<ModulePaths>
<Include>
<ModulePath>.*Fabrikam.Math.dll</ModulePath>
<!-- Add more ModulePath nodes here. -->
</Include>
</ModulePaths>
下表顯示元件和成員可比對在程式代碼涵蓋範圍中包含或排除的各種方式。
XML 元素 | 它匹配的項目 |
---|---|
ModulePath | 匹配由元件名稱或檔案路徑指定的元件。 |
CompanyName | 依據 Company 屬性比對組件。 |
PublicKeyToken | 根據公鑰令牌比對已簽署的組件。 |
源 | 依定義它們的來源檔案路徑名稱來比對元素。 |
屬性 | 符合指定屬性的元素。 指定屬性的完整名稱,例如 <Attribute>^System\.Diagnostics\.DebuggerHiddenAttribute$</Attribute> 。如果您排除 CompilerGeneratedAttribute 屬性,則使用語言功能的程序代碼,例如 async 、await 、yield return 和自動實作屬性,都會從程式代碼涵蓋範圍分析中排除。 若要排除真正產生的程序代碼,請只排除 GeneratedCodeAttribute 屬性。 |
功能 | 依完整名稱比對程式、函式或方法,包括參數清單。 您也可以使用 正規表示式來匹配名稱的一部分。 例子: Fabrikam.Math.LocalMath.SquareRoot(double); (C#)Fabrikam::Math::LocalMath::SquareRoot(double) (C++) |
程式代碼涵蓋範圍格式
根據預設,程式代碼涵蓋範圍會收集並儲存在 .coverage
檔案中。 您也可以使用其他格式收集涵蓋範圍,包括 Xml 和 Cobertura。 不同的格式可能會在不同的編輯器和流程中有用。 您可以在 runsettings 檔案的
您也可以從命令列指定不同的格式,無論是在 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 會在測試二進位檔所在的目錄中搜尋和檢測所有原生二進位檔。 您可以指定應該搜尋二進位檔的其他目錄。 下列範例指定應該對來自 C:\temp
及其子目錄的所有原生二進位檔進行檢測和分析,除了以 Fabrikam.Math.dll
結尾的檔案。
<ModulePaths>
<IncludeDirectories>
<Directory Recursive="true">C:\temp</Directory>
</IncludeDirectories>
<Exclude>
<ModulePath>.*Fabrikam.Math.dll</ModulePath>
</Exclude>
</ModulePaths>
正則表達式
包含和排除節點會使用正則表達式,這與通配符不同。 所有匹配均不區分大小寫。 一些範例包括:
.* 匹配任何字元序列的字串
\. 匹配符號 “.”
\( \) 符合括弧 “( )”
\\ 符合檔案路徑分隔符 “\”
^ 匹配字符串開頭
$ 符合字串結尾
下列 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>