Personalizzare l'analisi della copertura del codice
Per impostazione predefinita, code coverage analizza tutti gli assembly di soluzione caricati durante gli unit test. È consigliabile usare questo comportamento predefinito, perché funziona correttamente nella maggior parte dei casi. Per ulteriori informazioni, vedere Utilizzare la copertura del codice per determinare la quantità di codice testata.
Per escludere il codice di test dai risultati del code coverage e includere solo il codice dell'applicazione, aggiungere l'attributo ExcludeFromCodeCoverageAttribute alla classe di test.
Per includere assembly che non fanno parte della soluzione, ottenere i file .pdb per questi assembly e copiarli nella stessa cartella dei file .dll assembly.
File delle impostazioni di esecuzione
Il file delle impostazioni di esecuzione è il file di configurazione usato dagli strumenti di unit test. Le impostazioni di code coverage avanzate vengono specificate in un file runsettings.
Per personalizzare il code coverage, seguire questa procedura:
Aggiungere un file di impostazioni di esecuzione alla soluzione. In Esplora soluzioni , scegliere Aggiungi>Nuovo Elementodal menu di scelta rapida della soluzione e selezionare File XML. Salvare il file con un nome, ad esempio CodeCoverage.runsettings.
Se non vengono visualizzati tutti i modelli di elemento, scegliere Mostra tutti i modellie quindi scegliere il modello di elemento.
Aggiungere il contenuto del file di esempio alla fine di questo articolo e quindi personalizzarlo in base alle esigenze, come descritto nelle sezioni seguenti.
Selezionare un file di impostazioni di esecuzione.
A partire da Visual Studio 2019 versione 16.4, è possibile impostare automaticamente un file di impostazioni di esecuzione nella radice del progetto. In caso contrario, nel menu Test , scegli Configura impostazioni di esecuzione, e poi scegli Seleziona il file runsettings a livello di soluzione. Per specificare un file di impostazioni di esecuzione per l'esecuzione di test dalla riga di comando, vedere Configurare unit test.
Quando si seleziona Analizza copertura del codice, le informazioni di configurazione vengono lette dal file di impostazioni di esecuzione.
Suggerimento
I risultati e la colorazione del codice precedenti non vengono nascosti automaticamente quando si eseguono test o si aggiorna il codice.
Per disattivare e attivare le impostazioni personalizzate, deselezionare o selezionare il file nel menu Test.
Per selezionare il file delle impostazioni di esecuzione, dal menu Test, scegliere Seleziona file di impostazioni. Per specificare un file di impostazioni di esecuzione per l'esecuzione di test dalla riga di comando, vedere Configurare unit test.
Quando si seleziona Analizza la copertura del codice, le informazioni di configurazione vengono lette dal file delle impostazioni di esecuzione.
Suggerimento
I risultati e la colorazione del codice precedenti non vengono nascosti automaticamente quando si eseguono test o si aggiorna il codice.
Per disattivare e attivare le impostazioni personalizzate, scegliere Test, Configura impostazioni di esecuzionee deselezionare o selezionare il nome del file.
Percorsi di ricerca dei simboli
Il code coverage richiede file di simboli (file con estensione pdb) per gli assembly. Per gli assembly compilati dalla soluzione, i file di simboli sono in genere presenti insieme ai file binari e il code coverage funziona automaticamente. In alcuni casi, potrebbe essere necessario includere gli assembly di riferimento nell'analisi della copertura del codice. In questi casi, i file con estensione pdb potrebbero non essere adiacenti ai file binari, ma è possibile specificare il percorso di ricerca dei simboli nel file runsettings.
<SymbolSearchPaths>
<Path>\\mybuildshare\builds\ProjectX</Path>
<!--More paths if required-->
</SymbolSearchPaths>
Nota
La risoluzione dei simboli può richiedere tempo, soprattutto quando si usa un percorso di file remoto con molti assembly. È pertanto consigliabile copiare file con estensione pdb nello stesso percorso locale dei file binari (.dll e .exe).
Includere o escludere assembly e membri
È possibile includere o escludere assembly o tipi e membri specifici dall'analisi della copertura del codice. Se la sezione Includi è vuota o omessa, vengono inclusi tutti gli assembly caricati e i file PDB associati. Se un assembly o un membro corrisponde a una clausola nella sezione Exclude, viene escluso dalla copertura del codice. La sezione Escludi ha la precedenza rispetto alla sezione Includi: se un assembly è elencato sia in Includi che in Escludi, non verrà incluso nella copertura del codice.
Ad esempio, il codice XML seguente esclude un singolo assembly specificandone il nome:
<ModulePaths>
<Exclude>
<ModulePath>.*Fabrikam.Math.UnitTest.dll</ModulePath>
<!-- Add more ModulePath nodes here. -->
</Exclude>
</ModulePaths>
Nell'esempio seguente viene specificato che è necessario includere solo un singolo assembly nel code coverage:
<ModulePaths>
<Include>
<ModulePath>.*Fabrikam.Math.dll</ModulePath>
<!-- Add more ModulePath nodes here. -->
</Include>
</ModulePaths>
La tabella seguente illustra i vari modi in cui gli assembly e i membri possono essere confrontati per l'inclusione o l'esclusione dalla copertura del codice.
Elemento XML | Elementi corrispondenti |
---|---|
ModulePath | Corrisponde agli assembly specificati dal nome dell'assembly o dal percorso del file. |
NomeAzienda | Trova la corrispondenza degli assembly in base all'attributo Company. |
PublicKeyToken | Corrisponde agli assembly firmati dal token di chiave pubblica. |
Fonte | Trova la corrispondenza degli elementi in base al nome del percorso del file di origine in cui sono definiti. |
Attributo | Trova la corrispondenza degli elementi con l'attributo specificato. Specificare il nome completo dell'attributo, ad esempio <Attribute>^System\.Diagnostics\.DebuggerHiddenAttribute$</Attribute> .Se si esclude l'attributo CompilerGeneratedAttribute, il codice che usa funzionalità del linguaggio come async , await , yield return e le proprietà implementate automaticamente vengono escluse dall'analisi del code coverage. Per escludere il codice effettivamente generato, escludere solo l'attributo GeneratedCodeAttribute. |
Funzione | Corrisponde a procedure, funzioni o metodi mediante nome completamente qualificato, compreso l'elenco dei parametri. È anche possibile trovare una corrispondenza con parte del nome usando un'espressione regolare . Esempi: Fabrikam.Math.LocalMath.SquareRoot(double); (C#)Fabrikam::Math::LocalMath::SquareRoot(double) (C++) |
Formati di code coverage
Per impostazione predefinita, il code coverage viene raccolto e salvato in un file .coverage
. È anche possibile raccogliere copertura usando altri formati, tra cui Xml e Cobertura. I diversi formati possono essere utili in diversi editor e pipeline. È possibile abilitarlo in runsettings aggiungendo <Format>Cobertura</Format>
o <Format>Xml</Format>
nella sezione di configurazione DataCollector nel file runsettings. Questo formato può essere visualizzato nella finestra dei risultati del code coverage in Visual Studio Enterprise.
È anche possibile specificare formati diversi dalla riga di comando specificandolo nel file runsettings o specificandolo in un parametro . Ad esempio, la riga di comando dotnet usa dotnet test --collect:"Code Coverage;Format=Cobertura"
. Per vstest usare vstest.console.exe /collect:"Code Coverage;Format=Cobertura"
. Il parametro collect sovrascriverà il formato specificato in runsettings.
Strumentazione nativa statica e dinamica
In Visual Studio 2022 versione 17.2 è stata aggiunta l'opzione per instrumentare il file binario nativo in modo statico (su disco). Nelle versioni precedenti è stata supportata solo la strumentazione dinamica, che spesso non è stata in grado di instrumentare i metodi. La strumentazione nativa statica è più stabile ed è consigliabile. La strumentazione nativa statica richiede l'abilitazione dell'opzione di link /PROFILE per tutti i progetti nativi per cui è necessaria la raccolta della copertura del codice.
È anche possibile abilitare la strumentazione statica nativa in runsettings aggiungendo <EnableStaticNativeInstrumentation>True</EnableStaticNativeInstrumentation>
sotto <CodeCoverage>
tag. Usare questo metodo per gli scenari della riga di comando.
Per impostazione predefinita, la strumentazione nativa dinamica è sempre abilitata. Se la strumentazione statica e dinamica è abilitata, Visual Studio tenta di instrumentare il codice C++ in modo statico, ma se non è possibile (ad esempio, quando l'opzione di collegamento /PROFILE
non è abilitata), verrà usata la strumentazione dinamica. È possibile disabilitare completamente la strumentazione nativa dinamica in runsettings aggiungendo <EnableDynamicNativeInstrumentation>False</EnableDynamicNativeInstrumentation>
in <CodeCoverage>
.
Quando la strumentazione nativa statica è abilitata, i file binari nativi verranno instrumentati e sostituiti sul disco prima dell'esecuzione del test. I file binari originali verranno ripristinati dopo l'esecuzione del test. È possibile disabilitare il ripristino dei file originali in runsettings aggiungendo <EnableStaticNativeInstrumentationRestore>False</EnableStaticNativeInstrumentationRestore>
sotto il tag <CodeCoverage>
. Questo può risultare particolarmente utile negli scenari di integrazione continua.
Quando la strumentazione nativa statica è abilitata, Visual Studio cercherà e instrumenterà tutti i file binari nativi nella directory in cui si trova il file binario di test. È possibile specificare directory aggiuntive in cui devono essere cercati i file binari. Nell'esempio seguente viene specificato che tutti i file binari nativi di C:\temp
e le relative sottodirectory devono essere instrumentati ad eccezione dei file che terminano con Fabrikam.Math.dll
.
<ModulePaths>
<IncludeDirectories>
<Directory Recursive="true">C:\temp</Directory>
</IncludeDirectories>
<Exclude>
<ModulePath>.*Fabrikam.Math.dll</ModulePath>
</Exclude>
</ModulePaths>
Espressioni regolari
I nodi di inclusione e di esclusione utilizzano espressioni regolari, che non sono gli stessi dei caratteri jolly. Tutte le corrispondenze non fanno distinzione tra maiuscole e minuscole. Ecco alcuni esempi:
.* corrisponde a una stringa di qualsiasi carattere
\. corrisponde a un punto "."
\( \) corrisponde alle parentesi "( )"
\\ corrisponde a un delimitatore di percorso file "\"
^ corrisponde all'inizio della stringa
$ corrisponde alla fine della stringa
Il codice XML seguente illustra come includere ed escludere assembly specifici usando espressioni regolari:
<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>
Il codice XML seguente illustra come includere ed escludere funzioni specifiche usando espressioni regolari:
<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>
Avvertimento
Se si verifica un errore in un'espressione regolare, ad esempio una parentesi senza caratteri di escape o senza corrispondenza, l'analisi del code coverage non verrà eseguita.
Per altre informazioni sulle espressioni regolari, vedere Usare espressioni regolari in Visual Studio.
File con estensione runsettings di esempio
Copiare questo codice e modificarlo in base alle proprie esigenze.
<?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>