Bagikan melalui


Menyesuaikan analisis cakupan kode

Secara default, cakupan kode menganalisis semua rakitan solusi yang dimuat selama pengujian unit. Sebaiknya Anda menggunakan perilaku default ini, karena sering kali 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 rakitan yang bukan bagian dari solusi Anda, dapatkan file .pdb untuk rakitan ini dan salin ke folder yang sama dengan file .dll rakitan.

Menjalankan file pengaturan

File pengaturan eksekusi 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:

  1. Tambahkan file pengaturan jalankan 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.

  2. Tambahkan konten dari file contoh di akhir artikel ini, lalu sesuaikan dengan kebutuhan Anda seperti yang dijelaskan di bagian berikutnya.

  3. Pilih file pengaturan eksekusi.

    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 Jalankan Pengaturan, lalu pilih Pilih File runsetting Solusi Lebar. 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.

    Tip

    Hasil cakupan kode dan pewarnaan kode sebelumnya tidak disembunyikan secara otomatis saat Anda menjalankan pengujian atau memperbarui kode.

    Untuk mengaktifkan dan menonaktifkan pengaturan kustom, batalkan pilihan atau pilih file pada menu Pengujian.

    Untuk memilih file pengaturan eksekusi, pada menu Pengujian, 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.

    Tip

    Hasil cakupan kode dan pewarnaan kode sebelumnya tidak disembunyikan secara otomatis saat Anda menjalankan pengujian atau memperbarui kode.

    Untuk menonaktifkan dan mengaktifkan pengaturan kustom, pilih Uji, Konfigurasikan Jalankan Pengaturan, dan batal pilih 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 di samping file biner, dan cakupan kode bekerja secara otomatis. Dalam beberapa kasus, Anda mungkin ingin menyertakan rakitan yang direferensikan dalam analisis cakupan kode Anda. Dalam kasus seperti itu, file .pdb mungkin tidak berdekatan dengan biner, tetapi Anda dapat menentukan jalur pencarian simbol di file .runsettings.

<SymbolSearchPaths>
      <Path>\\mybuildshare\builds\ProjectX</Path>
      <!--More paths if required-->
</SymbolSearchPaths>

Catatan

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 rakitan dan anggota

Anda dapat menyertakan atau mengecualikan rakitan atau jenis dan anggota tertentu dari analisis cakupan kode. Jika bagian Sertakan kosong atau dihilangkan, semua rakitan yang dimuat dan memiliki file PDB terkait disertakan. Jika majelis atau anggota cocok dengan klausul di bagian Kecualikan, itu dikecualikan dari cakupan kode. Bagian Kecualikan lebih diutamakan daripada bagian Sertakan: jika rakitan tercantum di Sertakan dan Kecualikan, rakitan tersebut 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 menetapkan 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 majelis dan anggota dapat dicocokkan untuk dimasukkan atau dikeluarkan dari cakupan kode.

Elemen XML Apa yang cocok dengannya
ModulePath Mencocokkan rakitan yang ditentukan oleh nama rakitan atau jalur file.
NamaPerusahaan Cocokkan rakitan dengan atribut Perusahaan.
PublicKeyToken Mencocokkan rakitan yang ditandatangani oleh token kunci umum.
Sumber Mencocokkan elemen dengan nama jalur file sumber tempat elemen tersebut ditentukan.
Atribut Mencocokkan 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 diterapkan secara otomatis dikecualikan dari analisis cakupan kode. Untuk mengecualikan kode yang benar-benar dibuat, hanya kecualikan atribut GeneratedCodeAttribute.
Function Mencocokkan prosedur, fungsi, atau metode dengan nama yang sepenuhnya memenuhi syarat, termasuk daftar parameter. Anda juga dapat mencocokkan sebagian nama menggunakan regex.

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 untuk editor dan alur yang berbeda. Anda dapat mengaktifkan ini di runsettings 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 di file runsettings atau menentukannya dalam parameter. Misalnya, baris perintah dotnet menggunakan dotnet test --collect:"Code Coverage;Format=Cobertura". Untuk vstest menggunakan vstest.console.exe /collect:"Code Coverage;Format=Cobertura". Parameter collect akan menggantikan format yang ditentukan dalam runsettings.

Instrumentasi asli statis dan dinamis

Di Visual Studio 2022 versi 17.2, kami menambahkan opsi ke instrumen biner asli secara statis (pada disk). Pada versi sebelumnya, kami hanya mendukung instrumentasi dinamis, yang seringkali tidak dapat digunakan untuk metode instrumentasi. Instrumentasi asli statis lebih stabil dan direkomendasikan. Instrumentasi asli statis memerlukan pengaktifan opsi tautan /PROFILE untuk semua proyek asli yang Anda perlukan kumpulan cakupan kodenya.

Anda dapat mengaktifkan instrumentasi statis asli dengan mengaktifkan fitur pratinjau Cakupan Kode instrumentasi statis asli di Alat > Opsi > Lingkungan > Fitur Pratinjau .

Anda juga dapat mengaktifkan instrumentasi statis asli di runsettings 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 menginstrumentasikan kode C++ Anda secara statis, tetapi jika ini tidak memungkinkan (misalnya, saat opsi tautan /PROFILE tidak diaktifkan), instrumentasi dinamis akan digunakan. Anda dapat sepenuhnya menonaktifkan instrumentasi asli dinamis di runsettings dengan menambahkan <EnableDynamicNativeInstrumentation>False</EnableDynamicNativeInstrumentation> di bawah <CodeCoverage> .

Ketika instrumentasi asli statis diaktifkan, biner asli akan diinstrumentasi dan diganti pada disk sebelum eksekusi pengujian. Biner asli akan dikembalikan setelah eksekusi pengujian. Anda dapat menonaktifkan pemulihan file asli di pengaturan berjalan 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 menginstrumentasikan semua biner asli di direktori tempat biner uji berada. Anda dapat menentukan direktori tambahan di mana biner harus dicari. Contoh berikut menetapkan bahwa semua binari asli dari C:\temp dan subdirektorinya harus diinstrumentasi kecuali file yang diakhiri dengan Fabrikam.Math.dll .

<ModulePaths>
  <IncludeDirectories>
    <Directory Recursive="true">C:\temp</Directory>
  </IncludeDirectories>
  <Exclude>
    <ModulePath>.*Fabrikam.Math.dll</ModulePath>
  </Exclude>
</ModulePaths>

Regex

Menyertakan dan mengecualikan node menggunakan regex, yang tidak sama dengan wildcard. Semua kecocokan tidak peka huruf besar/kecil. Beberapa contohnya adalah:

  • .* cocok dengan string karakter apa pun

  • \. cocok dengan titik "."

  • \( \) cocok dengan tanda kurung "( )"

  • \\ cocok dengan pemisah jalur file "\"

  • ^ cocok dengan awal string

  • $ cocok dengan akhir string

XML berikut menunjukkan cara menyertakan dan mengecualikan rakitan tertentu menggunakan regex:

<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 menggunakan regex:

<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 lolos atau tidak cocok, analisis cakupan kode tidak akan berjalan.

Untuk informasi selengkapnya tentang regex, lihat Menggunakan regex di Visual Studio.

Sampel file .runsettings

Salin kode ini dan edit sesuai 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>
<!--
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>