Menyesuaikan analisis cakupan kode
Secara default, cakupan kode menganalisis semua rakitan solusi yang dimuat selama pengujian unit. Kami menyarankan agar Anda menggunakan perilaku default ini, karena sebagian besar waktu berfungsi dengan baik. Untuk informasi selengkapnya, lihat Menggunakan cakupan kode untuk menentukan berapa banyak kode yang diuji.
Untuk mengecualikan kode pengujian dari hasil cakupan kode dan hanya menyertakan kode aplikasi, tambahkan atribut ExcludeFromCodeCoverageAttribute ke kelas pengujian Anda.
Untuk menyertakan assembly yang bukan bagian dari solusi Anda, dapatkan file .pdb untuk assembly ini dan salin ke folder yang sama dengan file assembly .dll.
Nota
Cakupan kode hanya tersedia dengan Visual Studio Enterprise. Untuk cakupan kode .NET, Anda dapat menggunakan alat baris perintah, dotnet-coverage.
Jalankan file pengaturan
File pengaturan yang dijalankan adalah file konfigurasi yang digunakan oleh alat pengujian unit. Pengaturan cakupan kode tingkat lanjut ditentukan dalam file .runsettings.
Untuk menyesuaikan cakupan kode, ikuti langkah-langkah berikut:
Tambahkan file pengaturan eksekusi ke solusi Anda. Di Penjelajah Solusi, pada menu pintasan solusi Anda, pilih Tambahkan>Item Baru, dan pilih File XML. Simpan file dengan nama seperti CodeCoverage.runsettings.
Jika Anda tidak melihat semua templat item, pilih Perlihatkan Semua Templat, lalu pilih templat item.
Tambahkan konten dari file contoh di akhir artikel ini, lalu sesuaikan dengan kebutuhan Anda seperti yang dijelaskan di bagian berikut.
Pilih file pengaturan jalankan.
Mulai dari Visual Studio 2019 versi 16.4, Anda dapat secara otomatis memetakan file pengaturan eksekusi di akar proyek. Jika tidak, pada menu Uji, pilih Konfigurasikan Pengaturan Eksekusi, lalu pilih Pilih File runsettings Solusi Luas. Untuk menentukan file pengaturan eksekusi untuk menjalankan pengujian dari baris perintah, lihat Mengonfigurasi pengujian unit.
Saat Anda memilih Analisis Cakupan Kode, informasi konfigurasi dibaca dari file pengaturan eksekusi.
Tips
Setiap hasil cakupan kode sebelumnya dan pewarnaan kode tidak disembunyikan secara otomatis saat Anda menjalankan pengujian atau memperbarui kode Anda.
Untuk menonaktifkan dan mengaktifkan pengaturan kustom, batalkan pilihan atau pilih file pada menu Uji.
Untuk memilih file pengaturan eksekusi, pada menu Uji, pilih Pilih File Pengaturan. Untuk menentukan file pengaturan eksekusi untuk menjalankan pengujian dari baris perintah, lihat Mengonfigurasi pengujian unit.
Saat Anda memilih Analisis Cakupan Kode, informasi konfigurasi dibaca dari file pengaturan eksekusi.
Tips
Setiap hasil cakupan kode sebelumnya dan pewarnaan kode tidak disembunyikan secara otomatis saat Anda menjalankan pengujian atau memperbarui kode Anda.
Untuk menonaktifkan dan mengaktifkan pengaturan khusus, pilih Uji, Konfigurasikan Pengaturan Eksekusi, dan batalkan pilihan atau pilih nama file.
Jalur pencarian simbol
Cakupan kode memerlukan file simbol (file .pdb) untuk rakitan. Untuk rakitan yang dibangun oleh solusi Anda, file simbol biasanya ada bersama file biner, dan cakupan kode berfungsi secara otomatis. Dalam beberapa kasus, Anda mungkin ingin menyertakan rakitan yang dirujuk dalam analisis cakupan kode Anda. Dalam kasus seperti itu, file .pdb mungkin tidak berdekatan dengan biner, tetapi Anda dapat menentukan jalur pencarian simbol dalam file .runsettings.
<SymbolSearchPaths>
<Path>\\mybuildshare\builds\ProjectX</Path>
<!--More paths if required-->
</SymbolSearchPaths>
Nota
Resolusi simbol dapat memakan waktu, terutama saat menggunakan lokasi file jarak jauh dengan banyak rakitan. Oleh karena itu, pertimbangkan untuk menyalin file .pdb ke lokasi lokal yang sama dengan file biner (.dll dan .exe).
Menyertakan atau mengecualikan assemblies dan anggota
Anda dapat menyertakan atau mengecualikan rakitan atau jenis dan anggota tertentu dari analisis cakupan kode. Jika bagian Sertakan kosong atau dihilangkan, maka semua assembly yang dimuat dan yang memiliki file PDB terkait juga disertakan. Jika rakitan atau anggota cocok dengan klausul di bagian Kecualikan, maka itu dikecualikan dari cakupan kode. Bagian Kecuali diutamakan daripada bagian Termasuk: jika assembly tercantum di Termasuk dan Kecuali, tidak akan disertakan dalam cakupan kode.
Misalnya, XML berikut mengecualikan satu rakitan dengan menentukan namanya:
<ModulePaths>
<Exclude>
<ModulePath>.*Fabrikam.Math.UnitTest.dll</ModulePath>
<!-- Add more ModulePath nodes here. -->
</Exclude>
</ModulePaths>
Contoh berikut menentukan bahwa hanya satu rakitan yang harus disertakan dalam cakupan kode:
<ModulePaths>
<Include>
<ModulePath>.*Fabrikam.Math.dll</ModulePath>
<!-- Add more ModulePath nodes here. -->
</Include>
</ModulePaths>
Tabel berikut menunjukkan berbagai cara agar komponen dan anggota dapat sesuai untuk dimasukkan atau dikecualikan dari cakupan kode.
Elemen XML | Apa yang cocok dengannya |
---|---|
ModulePath | Cocok dengan rakitan yang ditentukan oleh nama rakitan atau jalur file. |
CompanyName | Mencocokkan rakitan dengan atribut Perusahaan. |
PublicKeyToken | Mencocokkan assembly yang ditandatangani berdasarkan token kunci publik. |
Sumber | Mencocokkan elemen dengan nama jalur file sumber tempat mereka ditentukan. |
Atribut | Cocok dengan elemen yang memiliki atribut yang ditentukan. Tentukan nama lengkap atribut, misalnya <Attribute>^System\.Diagnostics\.DebuggerHiddenAttribute$</Attribute> .Jika Anda mengecualikan atribut CompilerGeneratedAttribute, kode yang menggunakan fitur bahasa seperti async , await , yield return , dan properti yang diimplementasikan secara otomatis dikecualikan dari analisis cakupan kode. Untuk mengecualikan kode yang benar-benar dihasilkan, hanya kecualikan atribut GeneratedCodeAttribute. |
Fungsi | Mencocokkan prosedur, fungsi, atau metode dengan nama yang sesuai sepenuhnya, termasuk daftar parameter. Anda juga dapat mencocokkan bagian dari nama dengan menggunakan ekspresi reguler . Contoh: Fabrikam.Math.LocalMath.SquareRoot(double); (C#)Fabrikam::Math::LocalMath::SquareRoot(double) (C++) |
Format cakupan kode
Secara default cakupan kode dikumpulkan dan disimpan dalam file .coverage
. Anda juga dapat mengumpulkan cakupan menggunakan format lain termasuk Xml dan Cobertura. Format yang berbeda mungkin berguna di berbagai editor dan alur. Anda dapat mengaktifkan ini dalam runsetting dengan menambahkan <Format>Cobertura</Format>
atau <Format>Xml</Format>
di bagian konfigurasi DataCollector di file runsettings Anda. Format ini dapat dilihat di jendela hasil cakupan kode di Visual Studio Enterprise.
Anda juga dapat menentukan format yang berbeda dari baris perintah dengan menentukannya dalam file runsettings atau menentukannya dalam parameter. Misalnya, baris perintah dotnet menggunakan dotnet test --collect:"Code Coverage;Format=Cobertura"
. Untuk vstest, gunakan vstest.console.exe /collect:"Code Coverage;Format=Cobertura"
. Parameter kumpulkan akan menggantikan format yang ditentukan dalam runsettings.
Instrumentasi asli statis dan dinamis
Di Visual Studio 2022 versi 17.2, kami menambahkan opsi untuk melengkapi biner asli secara statis (pada disk). Dalam versi sebelumnya, kami hanya mendukung instrumentasi dinamis, yang seringkali tidak dapat menginstrumen metode. Instrumentasi asli statis lebih stabil dan disarankan. Instrumentasi asli statis memerlukan pengaktifan opsi tautan /PROFILE untuk semua proyek asli di mana Anda memerlukan pengumpulan cakupan kode.
Anda juga dapat mengaktifkan instrumentasi statis asli dalam runsetting dengan menambahkan <EnableStaticNativeInstrumentation>True</EnableStaticNativeInstrumentation>
di bawah tag <CodeCoverage>
. Gunakan metode ini untuk skenario baris perintah.
Secara default, instrumentasi asli dinamis selalu diaktifkan. Jika instrumentasi statis dan dinamis diaktifkan, Visual Studio mencoba melengkapi kode C++ Anda secara statis, tetapi jika ini tidak memungkinkan (misalnya, ketika opsi tautan /PROFILE
tidak diaktifkan), instrumentasi dinamis akan digunakan. Anda dapat sepenuhnya menonaktifkan instrumentasi asli dinamis dalam runsettings dengan menambahkan <EnableDynamicNativeInstrumentation>False</EnableDynamicNativeInstrumentation>
di bawah <CodeCoverage>
.
Ketika instrumentasi asli statis diaktifkan, biner asli akan diinstrumentasikan dan diganti pada disk sebelum eksekusi pengujian. File biner asli akan dipulihkan setelah eksekusi pengujian. Anda dapat menonaktifkan pemulihan file asli dalam runsetting dengan menambahkan <EnableStaticNativeInstrumentationRestore>False</EnableStaticNativeInstrumentationRestore>
di bawah tag <CodeCoverage>
. Ini bisa sangat berguna dalam skenario CI.
Ketika instrumentasi asli statis diaktifkan, Visual Studio akan mencari dan menginstrumen semua biner asli di semua direktori tempat biner pengujian berada. Anda dapat menentukan direktori tambahan di mana file biner harus dicari. Contoh berikut menentukan bahwa semua biner asli dari C:\temp
dan subdirektorinya harus diinstrumentasikan kecuali file yang berakhiran dengan Fabrikam.Math.dll
.
<ModulePaths>
<IncludeDirectories>
<Directory Recursive="true">C:\temp</Directory>
</IncludeDirectories>
<Exclude>
<ModulePath>.*Fabrikam.Math.dll</ModulePath>
</Exclude>
</ModulePaths>
Ekspresi Reguler
Sertakan dan mengecualikan simpul menggunakan ekspresi reguler, yang tidak sama dengan karakter pengganti. Semua pencocokan bersifat tidak peka terhadap huruf besar/kecil. Beberapa contohnya adalah:
.* cocok dengan string karakter apa pun
\. cocok dengan titik "."
\( \) cocok dengan tanda kurung "( )"
\\ cocok dengan pemisah jalur berkas "\\"
^ cocok dengan awal string
$ cocok dengan akhir string
XML berikut menunjukkan cara menyertakan dan mengecualikan rakitan tertentu dengan menggunakan ekspresi reguler:
<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 berikut menunjukkan cara menyertakan dan mengecualikan fungsi tertentu dengan menggunakan ekspresi reguler:
<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>
Peringatan
Jika ada kesalahan dalam ekspresi reguler, seperti tanda kurung yang tidak dilewati atau tidak cocok, analisis cakupan kode tidak akan berjalan.
Untuk informasi selengkapnya tentang ekspresi reguler, lihat Menggunakan ekspresi reguler di Visual Studio.
Contoh file .runsettings
Salin kode ini dan edit agar sesuai dengan kebutuhan Anda.
<?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>