Delen via


Analyse van codedekking aanpassen

Standaard analyseert codedekking alle oplossingsassembly's die tijdens eenheidstests worden geladen. We raden u aan dit standaardgedrag te gebruiken, omdat dit meestal goed werkt. Zie Codedekking gebruiken om te bepalen hoeveel code is getestvoor meer informatie.

Als u testcode wilt uitsluiten van de resultaten van de codedekking en alleen toepassingscode wilt opnemen, voegt u het kenmerk ExcludeFromCodeCoverageAttribute toe aan uw testklasse.

Als u assembly's wilt opnemen die geen deel uitmaken van uw oplossing, haalt u de .pdb- bestanden voor deze assembly's op en kopieert u deze naar dezelfde map als de assembly-.dll-bestanden.

Voer instellingenbestand uit

Het bestand met instellingen is het configuratiebestand dat wordt gebruikt door hulpprogramma's voor eenheidstests. Geavanceerde instellingen voor codedekking worden opgegeven in een .runsettings--bestand.

Volg deze stappen om de codedekking aan te passen:

  1. Voeg een bestand met uitvoeringsinstellingen toe aan uw oplossing. Kies in Solution Explorerin het snelmenu van uw oplossing Toevoegen>nieuw itemen selecteer XML-bestand. Sla het bestand op met een naam zoals CodeCoverage.runsettings.

    Als u niet alle itemsjablonen ziet, kiest u Alle sjablonen weergevenen kiest u vervolgens de itemsjabloon.

  2. Voeg de inhoud uit het voorbeeldbestand aan het einde van dit artikel toe en pas deze vervolgens aan uw behoeften aan, zoals wordt beschreven in de volgende secties.

  3. Selecteer een bestand met uitvoeringsinstellingen.

    Vanaf Visual Studio 2019 versie 16.4 kunt u automatisch een bestand met uitvoeringsinstellingen detecteren in de hoofdmap van het project. Anders kies in het menu Test de optie Instellingen uitvoeren configurerenen kies daarna de optie Solution Wide uitvoerinstellingenbestand selecteren. Zie Configureer eenheidstestsom een uitvoeringsinstellingenbestand op te geven voor het uitvoeren van tests vanaf de opdrachtregel.

    Wanneer u Codedekking Analyserenselecteert, worden de configuratiegegevens gelezen uit het uitvoeringsinstellingenbestand.

    Tip

    Eventuele eerdere codedekkingsresultaten en codekleuring worden niet automatisch verborgen wanneer u tests uitvoert of uw code bijwerkt.

    Als u de aangepaste instellingen wilt in- en uitschakelen, deselecteert of selecteert u het bestand in het menu Test.

    Als u het bestand met uitvoeringsinstellingen wilt selecteren, kiest u in het menu TestInstellingenbestand selecteren. Zie Configureer eenheidstestsom een uitvoeringsinstellingenbestand op te geven voor het uitvoeren van tests vanaf de opdrachtregel.

    Wanneer u Codedekking Analyserenselecteert, worden de configuratiegegevens gelezen uit het uitvoeringsinstellingenbestand.

    Tip

    Eventuele eerdere codedekkingsresultaten en codekleuring worden niet automatisch verborgen wanneer u tests uitvoert of uw code bijwerkt.

    Als u de aangepaste instellingen wilt in- en uitschakelen, kiest u Test, Instellingen voor uitvoeren configurerenen deselecteert of selecteert u de bestandsnaam.

Zoekpaden voor symbolen

Voor codedekking zijn symboolbestanden (.pdb--bestanden) vereist voor assembly's. Voor assembly's die door uw oplossing zijn gebouwd, zijn symboolbestanden meestal aanwezig naast de binaire bestanden en werkt de codedekking automatisch. In sommige gevallen wilt u mogelijk verwijzingen naar assembly's opnemen in uw codedekkingsanalyse. In dergelijke gevallen staan de .pdb--bestanden mogelijk niet naast de binaire bestanden, maar u kunt het zoekpad voor symbolen opgeven in het .runsettings--bestand.

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

Notitie

Symboolresolutie kan tijd in beslag nemen, met name bij het gebruik van een externe bestandslocatie met veel assembly's. Daarom kunt u overwegen om .pdb--bestanden te kopiëren naar dezelfde lokale locatie als de binaire bestanden (.dll en .exe).

Assemblages en leden opnemen of uitsluiten

U kunt assembly's of specifieke typen en leden opnemen of uitsluiten van de code-dekkingsanalyse. Als de sectie Opnemen leeg is of weggelaten, worden alle assembly's die zijn geladen en PDB-bestanden hebben, opgenomen. Als een assembly of lid overeenkomt met een clausule in de sectie Uitsluiten, wordt deze uitgesloten van codedekking. De sectie Uitsluiten heeft voorrang op de sectie Insluiten: als een assembly wordt vermeld in zowel Insluiten als Uitsluiten, wordt deze niet opgenomen in de code coverage.

Met de volgende XML wordt bijvoorbeeld één assembly uitgesloten door de naam ervan op te geven:

<ModulePaths>
  <Exclude>
   <ModulePath>.*Fabrikam.Math.UnitTest.dll</ModulePath>
   <!-- Add more ModulePath nodes here. -->
  </Exclude>
</ModulePaths>

In het volgende voorbeeld wordt aangegeven dat er slechts één assembly moet worden opgenomen in de codedekking:

<ModulePaths>
  <Include>
   <ModulePath>.*Fabrikam.Math.dll</ModulePath>
   <!-- Add more ModulePath nodes here. -->
  </Include>
</ModulePaths>

In de volgende tabel ziet u de verschillende manieren waarop assembly's en leden kunnen worden vergeleken voor opname in of uitsluiting van codedekking.

XML-element Waar komt het mee overeen
ModulePath Komt overeen met assemblies die zijn opgegeven door de assemblynaam of het bestandspad.
Bedrijfsnaam Komt overeen met samenstellingen op basis van het kenmerk Company.
PublicKeyToken Herkent ondertekende assembly's met het token van de openbare sleutel.
Bron Komt overeen met elementen op basis van de padnaam van het bronbestand waarin ze zijn gedefinieerd.
Attribuut Komt overeen met elementen met het opgegeven kenmerk. Geef de volledige naam van het kenmerk op, bijvoorbeeld <Attribute>^System\.Diagnostics\.DebuggerHiddenAttribute$</Attribute>.

Als u het kenmerk CompilerGeneratedAttribute uitsluit, wordt code die gebruikmaakt van taalfuncties zoals async, await, yield returnen automatisch geïmplementeerde eigenschappen uitgesloten van codedekkingsanalyse. Als u echt gegenereerde code wilt uitsluiten, sluit u alleen het kenmerk GeneratedCodeAttribute uit.
Functie Komt overeen met procedures, functies of methoden aan de hand van de volledig gekwalificeerde naam, inclusief de parameterslijst. U kunt ook een deel van de naam vergelijken met behulp van een reguliere expressie.

Voorbeelden:

Fabrikam.Math.LocalMath.SquareRoot(double); (C#)

Fabrikam::Math::LocalMath::SquareRoot(double) (C++)

Indelingen voor codedekking

Standaard wordt de codedekking verzameld en opgeslagen in een .coverage-bestand. U kunt ook dekking verzamelen met andere indelingen, waaronder Xml en Cobertura. Verschillende indelingen kunnen handig zijn voor verschillende editors en pijplijnen. U kunt dit inschakelen in runsettings door <Format>Cobertura</Format> of <Format>Xml</Format> toe te voegen in de sectie DataCollector-configuratie in uw runettings-bestand. Deze indeling kan worden weergegeven in het venster met resultaten van de codedekking in Visual Studio Enterprise.

U kunt ook verschillende indelingen opgeven vanaf de opdrachtregel door deze op te geven in het runettings-bestand of door het op te geven in een parameter. De dotnet-opdrachtregel gebruikt bijvoorbeeld dotnet test --collect:"Code Coverage;Format=Cobertura". Gebruik voor vstest vstest.console.exe /collect:"Code Coverage;Format=Cobertura". De parameter collect overschrijft de indeling die is opgegeven in runsettings.

Statische en dynamische systeemeigen instrumentatie

In Visual Studio 2022 versie 17.2 hebben we de optie toegevoegd om systeemeigen binair statisch te instrumenteren (op schijf). In eerdere versies hebben we alleen dynamische instrumentatie ondersteund, die vaak niet in staat was om methoden te instrumenteren. Statische systeemeigen instrumentatie is stabieler en wordt aanbevolen. Statische systeemeigen instrumentatie vereist het inschakelen van de koppelingsoptie /PROFILE voor alle systeemeigen projecten waarvoor u codedekkingsverzameling nodig hebt.

U kunt ook systeemeigen statische instrumentatie in runsettings inschakelen door <EnableStaticNativeInstrumentation>True</EnableStaticNativeInstrumentation> toe te voegen onder <CodeCoverage> tag. Gebruik deze methode voor opdrachtregelscenario's.

Dynamische systeemeigen instrumentatie is standaard altijd ingeschakeld. Als zowel statische als dynamische instrumentatie is ingeschakeld, probeert Visual Studio uw C++-code statisch te instrumenteren, maar als dit niet mogelijk is (bijvoorbeeld wanneer de optie /PROFILE koppeling niet is ingeschakeld), wordt dynamische instrumentatie gebruikt. U kunt dynamische systeemeigen instrumentatie volledig uitschakelen in runsettings door <EnableDynamicNativeInstrumentation>False</EnableDynamicNativeInstrumentation> toe te voegen onder <CodeCoverage>.

Wanneer statische systeemeigen instrumentatie is ingeschakeld, worden systeemeigen binaire bestanden geïnstrumenteerd en vervangen op schijf voordat de test wordt uitgevoerd. Oorspronkelijke binaire bestanden worden hersteld na de testuitvoering. U kunt het herstellen van oorspronkelijke bestanden in runsettings uitschakelen door <EnableStaticNativeInstrumentationRestore>False</EnableStaticNativeInstrumentationRestore> toe te voegen onder de tag <CodeCoverage>. Dit kan met name handig zijn in CI-scenario's.

Wanneer statische systeemeigen instrumentatie is ingeschakeld, zoekt En instrumenteert Visual Studio alle systeemeigen binaire bestanden in de map waar het binaire testbestand zich bevindt. U kunt extra mappen opgeven waarin binaire bestanden moeten worden doorzocht. In het volgende voorbeeld wordt aangegeven dat alle systeemeigen binaire bestanden uit C:\temp en de bijbehorende submappen moeten worden geïnstrueerd, behalve bestanden die eindigen op Fabrikam.Math.dll.

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

Reguliere expressies

Het opnemen en uitsluiten van knooppunten gebeurt met behulp van reguliere expressies, welke niet hetzelfde zijn als jokertekens. Alle overeenkomsten zijn hoofdlettergevoelig. Enkele voorbeelden zijn:

  • .* komt overeen met een tekenreeks van willekeurige tekens

  • \. komt overeen met een punt "."

  • \( \) komt overeen met haakjes "( )"

  • \\ komt overeen met een bestandspadscheidingsteken "\"

  • ^ komt overeen met het begin van de tekenreeks

  • $ komt overeen met het einde van de string

In de volgende XML ziet u hoe u specifieke assembly's kunt opnemen en uitsluiten met behulp van reguliere expressies:

<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>

In de volgende XML ziet u hoe u specifieke functies kunt opnemen en uitsluiten met behulp van reguliere expressies:

<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>

Waarschuwing

Als er een fout optreedt in een reguliere expressie, zoals een niet-gescaped of niet-overeenkomend haakje, wordt de codedekkingsanalyse niet uitgevoerd.

Zie Reguliere expressies gebruiken in Visual Studiovoor meer informatie over reguliere expressies.

Voorbeeldbestand .runsettings

Kopieer deze code en bewerk deze naar wens.

<?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>