Dela via


Anpassa kodtäckningsanalys

Som standard analyserar kodtäckning alla lösningssammansättningar som läses in under enhetstester. Vi rekommenderar att du använder det här standardbeteendet eftersom det fungerar bra för det mesta. Mer information finns i Använda kodtäckning för att avgöra hur mycket kod som testas.

Om du vill undanta testkoden från kodtäckningsresultatet och endast inkludera programkod lägger du till attributet ExcludeFromCodeCoverageAttribute i testklassen.

Om du vill inkludera sammansättningar som inte ingår i lösningen hämtar du .pdb- filer för dessa sammansättningar och kopierar dem till samma mapp som sammansättningen .dll filer.

Kör inställningsfil

Körinställningsfilen är konfigurationsfilen som används av verktyg för enhetstestning. Avancerade inställningar för kodtäckning anges i en .runsettings-fil.

Följ dessa steg för att anpassa kodtäckningen:

  1. Lägg till en körningskonfigurationsfil i din lösning. I Solution Explorergår du till snabbmenyn i lösningen och väljer Lägg till>Nytt objektoch väljer XML-fil. Spara filen med ett namn som CodeCoverage.runsettings.

    Om du inte ser alla objektmallar väljer du Visa alla mallaroch väljer sedan objektmallen.

  2. Lägg till innehållet från exempelfilen i slutet av den här artikeln och anpassa det sedan efter dina behov enligt beskrivningen i avsnitten som följer.

  3. Välj en körningsinställningsfil.

    Från och med Visual Studio 2019 version 16.4 kan du automatiskt identifiera en körfil i projektroten. På menyn Test, välj annars Konfigurera körningsinställningaroch välj sedan Välj lösningsomfattande runsettings-fil. Information om hur du anger en körningsinställningsfil för att köra tester från kommandoraden finns i Konfigurera enhetstester.

    När du väljer Analysera kodtäckningläses konfigurationsinformationen från körinställningsfilen.

    Tips

    Tidigare resultat av kodtäckning och kodfärgning döljs inte automatiskt när du kör tester eller uppdaterar koden.

    Om du vill inaktivera och aktivera anpassade inställningar avmarkerar eller väljer du filen på menyn Test.

    Välj körinställningsfilen genom att välja Välj inställningsfilpå menyn Test . Information om hur du anger en körningsinställningsfil för att köra tester från kommandoraden finns i Konfigurera enhetstester.

    När du väljer Analysera kodtäckningläses konfigurationsinformationen från körningsinställningsfilen.

    Tips

    Tidigare resultat av kodtäckning och kodfärgning döljs inte automatiskt när du kör tester eller uppdaterar koden.

    Om du vill inaktivera och aktivera anpassade inställningar väljer du Test, Konfigurera körningsinställningaroch avmarkerar eller väljer filnamnet.

Sökvägar för symbolsökning

Kodtäckning kräver symbolfiler (.pdb-filer) för sammansättningar. För sammansättningar som skapats av din lösning finns symbolfiler vanligtvis tillsammans med binära filer och kodtäckningen fungerar automatiskt. I vissa fall kanske du vill inkludera refererade sammansättningar i din kodtäckningsanalys. I sådana fall kanske .pdb- filer inte ligger i närheten av binärfilerna, men du kan ange sökvägen för symbolsökningen i .runsettings-filen.

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

Not

Symbolmatchning kan ta tid, särskilt när du använder en fjärrfilplats med många sammansättningar. Överväg därför att kopiera .pdb- filer till samma lokala plats som binärfilerna (.dll och .exe).

Inkludera eller exkludera sammansättningar och medlemmar

Du kan inkludera eller exkludera sammansättningar eller specifika typer och medlemmar från kodtäckningsanalys. Om avsnittet Include är tomt eller utelämnat inkluderas alla sammansättningar som läses in och har associerade PDB-filer. Om en sammansättning eller medlem matchar en sats i avsnittet Exkludera undantas den från kodtäckningen. Avsnittet Exclude har företräde framför avsnittet Include (Inkludera): om en sammansättning visas i både Inkludera och Exkluderatas den inte med i kodtäckningen.

Följande XML exkluderar till exempel en enskild sammansättning genom att ange dess namn:

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

I följande exempel anges att endast en enskild sammansättning ska ingå i kodtäckningen:

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

I följande tabell visas de olika sätt som sammansättningar och medlemmar kan matchas för inkludering i eller exkludering från kodtäckning.

XML-element Vad det passar med
ModulePath Matchar sammansättningar som anges med sammansättningsnamn eller filsökväg.
CompanyName Matchar sammansättningar med attributet Company.
PublicKeyToken Matchar signerade sammansättningar med den offentliga nyckeltoken.
Källa Elementen matchas efter sökvägen för den källfil där de definieras.
Attribut Matchar element som har det angivna attributet. Ange det fullständiga namnet på attributet, till exempel <Attribute>^System\.Diagnostics\.DebuggerHiddenAttribute$</Attribute>.

Om du exkluderar attributet CompilerGeneratedAttribute undantas kod som använder språkfunktioner som async, await, yield returnoch automatiskt implementerade egenskaper från kodtäckningsanalys. Om du vill exkludera verkligt genererad kod undantar du bara attributet GeneratedCodeAttribute.
Funktion Matchar procedurer, funktioner eller metoder med fullständigt kvalificerat namn, inklusive parameterlistan. Du kan också matcha en del av namnet med hjälp av ett reguljärt uttryck.

Exempel:

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

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

Kodtäckningsformat

Som standardinställning samlas kodtäckning in och sparas i .coverage-filen. Du kan också samla in täckning med andra format, inklusive Xml och Cobertura. Olika format kan vara användbara i olika redigeringsprogram och pipelines. Du kan aktivera detta i runsettings genom att lägga till <Format>Cobertura</Format> eller <Format>Xml</Format> i konfigurationsavsnittet för DataCollector i din runsettings-fil. Det här formatet kan visas i resultatfönstret för kodtäckning i Visual Studio Enterprise.

Du kan också ange olika format från kommandoraden genom att antingen ange det i filen runsettings eller ange det i en parameter. Till exempel använder dotnet-kommandoraden dotnet test --collect:"Code Coverage;Format=Cobertura". För vstest använder du vstest.console.exe /collect:"Code Coverage;Format=Cobertura". Parametern 'collect' kommer att åsidosätta formatet som anges i runsettings.

Statisk och dynamisk intern instrumentation

I Visual Studio 2022 version 17.2 lade vi till alternativet att instrumentera inbyggt binärt statiskt (på disk). I tidigare versioner stödde vi endast dynamisk instrumentering, som ofta inte kunde instrumentera metoder. Den statiska inbyggda instrumentationen är stabilare och rekommenderas. Statisk intern instrumentation kräver aktivering av alternativet /PROFILE länk för alla interna projekt som du behöver kodtäckningssamling för.

Du kan också aktivera inbyggd statisk instrumentering i runsettings genom att lägga till <EnableStaticNativeInstrumentation>True</EnableStaticNativeInstrumentation> under <CodeCoverage>-taggen. Använd den här metoden för kommandoradsscenarier.

Som standard är dynamisk intern instrumentation alltid aktiverad. Om både statisk och dynamisk instrumentation är aktiverad försöker Visual Studio instrumentera C++-koden statiskt, men om detta inte är möjligt (till exempel när alternativet /PROFILE länk inte är aktiverat) används dynamisk instrumentation. Du kan helt inaktivera dynamisk native instrumentering i runsettings genom att lägga till <EnableDynamicNativeInstrumentation>False</EnableDynamicNativeInstrumentation> under <CodeCoverage>.

När statisk inbyggd instrumentation är aktiverad kommer inhemska binärfiler att instrumenteras och ersättas på disken före testkörningen. Ursprungliga binärfiler återställs efter testkörningen. Du kan inaktivera återställning av ursprungliga filer i runsettings genom att lägga till <EnableStaticNativeInstrumentationRestore>False</EnableStaticNativeInstrumentationRestore> under taggen <CodeCoverage>. Detta kan vara särskilt användbart i CI-scenarier.

När statisk inbyggd instrumentering är aktiverad kommer Visual Studio att söka efter och instrumentera alla interna binärfiler i katalogen där testbinärfilen finns. Du kan ange ytterligare kataloger där binärfiler ska sökas igenom. I följande exempel anges att alla interna binärfiler från C:\temp och dess underkataloger ska instrumenteras förutom filer som slutar med Fabrikam.Math.dll.

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

Reguljära uttryck

Inkludera och exkludera noder använder reguljära uttryck, vilka inte är samma som jokertecken. Alla matchningar är skiftlägesokänsliga. Några exempel är:

  • .* matchar en sträng med vilka tecken som helst

  • \. matchar en punkt "."

  • \( \) matchar parenteser "( )"

  • \\ motsvarar en sökvägsavgränsare "\"

  • ^ överensstämmer med början av strängen

  • $ matchar slutet av strängen

Följande XML visar hur du inkluderar och exkluderar specifika sammansättningar med hjälp av reguljära uttryck:

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

Följande XML visar hur du inkluderar och exkluderar specifika funktioner med hjälp av reguljära uttryck:

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

Varning

Om det finns ett fel i ett reguljärt uttryck, till exempel en osläckad eller omatchad parentes, körs inte kodtäckningsanalys.

Mer information om reguljära uttryck finns i Använda reguljära uttryck i Visual Studio.

Exempel på .runsettings-fil

Kopiera den här koden och redigera den så att den passar dina behov.

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