Dostosowywanie analizy pokrycia kodu
Domyślnie pokrycie kodu analizuje wszystkie zestawy rozwiązań, które są ładowane podczas testów jednostkowych. Zalecamy użycie tego domyślnego zachowania, ponieważ działa ono przez większość czasu. Aby uzyskać więcej informacji, zobacz Używanie pokrycia kodu w celu określenia, ile kodu jest testowane.
Aby wykluczyć kod testowy z wyników pokrycia kodu i dołączyć tylko kod aplikacji, dodaj ExcludeFromCodeCoverageAttribute atrybut do klasy testowej.
Aby uwzględnić zestawy, które nie są częścią rozwiązania, uzyskaj pliki .pdb dla tych zestawów i skopiuj je do tego samego folderu co pliki dll zestawu.
Uruchom plik ustawień
Plik ustawień uruchamiania to plik konfiguracji używany przez narzędzia do testowania jednostkowego. Zaawansowane ustawienia pokrycia kodu są określone w pliku .runsettings .
Aby dostosować pokrycie kodu, wykonaj następujące kroki:
Dodaj plik ustawień uruchamiania do rozwiązania. W Eksplorator rozwiązań w menu skrótów rozwiązania wybierz pozycję Dodaj>nowy element i wybierz pozycję Plik XML. Zapisz plik pod nazwą, taką jak CodeCoverage.runsettings.
Jeśli nie widzisz wszystkich szablonów elementów, wybierz pozycję Pokaż wszystkie szablony, a następnie wybierz szablon elementu.
Dodaj zawartość z przykładowego pliku na końcu tego artykułu, a następnie dostosuj ją do swoich potrzeb zgodnie z opisem w poniższych sekcjach.
Wybierz plik ustawień uruchamiania.
Począwszy od programu Visual Studio 2019 w wersji 16.4, możesz automatycznie określić plik ustawień uruchamiania w katalogu głównym projektu. W przeciwnym razie w menu Test wybierz pozycję Konfiguruj uruchamianie Ustawienia, a następnie wybierz pozycję Wybierz plik ustawień szerokiego rozwiązania. Aby określić plik ustawień uruchamiania na potrzeby uruchamiania testów z poziomu wiersza polecenia, zobacz Konfigurowanie testów jednostkowych.
Po wybraniu pozycji Analizuj pokrycie kodu informacje o konfiguracji są odczytywane z pliku ustawień uruchamiania.
Napiwek
Wszystkie poprzednie wyniki pokrycia kodu i kolorowanie kodu nie są automatycznie ukryte podczas uruchamiania testów ani aktualizowania kodu.
Aby wyłączyć i włączyć ustawienia niestandardowe, usuń zaznaczenie lub wybierz plik w menu Test .
Aby wybrać plik ustawień uruchamiania, w menu Test wybierz pozycję Wybierz Ustawienia Plik. Aby określić plik ustawień uruchamiania na potrzeby uruchamiania testów z poziomu wiersza polecenia, zobacz Konfigurowanie testów jednostkowych.
Po wybraniu pozycji Analizuj pokrycie kodu informacje o konfiguracji są odczytywane z pliku ustawień uruchamiania.
Napiwek
Wszystkie poprzednie wyniki pokrycia kodu i kolorowanie kodu nie są automatycznie ukryte podczas uruchamiania testów ani aktualizowania kodu.
Aby wyłączyć i włączyć ustawienia niestandardowe, wybierz pozycję Testuj, Skonfiguruj uruchamianie Ustawienia i usuń zaznaczenie lub wybierz nazwę pliku.
Ścieżki wyszukiwania symboli
Pokrycie kodu wymaga plików symboli (plików pdb ) dla zestawów. W przypadku zestawów utworzonych przez rozwiązanie pliki symboli są zwykle obecne wraz z plikami binarnymi, a pokrycie kodu działa automatycznie. W niektórych przypadkach warto uwzględnić zestawy, do których odwołuje się analiza pokrycia kodu. W takich przypadkach pliki .pdb mogą nie sąsiadować z plikami binarnymi, ale można określić ścieżkę wyszukiwania symboli w pliku .runsettings .
<SymbolSearchPaths>
<Path>\\mybuildshare\builds\ProjectX</Path>
<!--More paths if required-->
</SymbolSearchPaths>
Uwaga
Rozpoznawanie symboli może zająć trochę czasu, zwłaszcza w przypadku korzystania ze zdalnej lokalizacji pliku z wieloma zestawami. W związku z tym należy rozważyć skopiowanie plików .pdb do tej samej lokalizacji lokalnej co pliki binarne (.dll i .exe).
Dołączanie lub wykluczanie zestawów i elementów członkowskich
Można dołączać lub wykluczać zestawy lub określone typy i elementy członkowskie z analizy pokrycia kodu. Jeśli sekcja Dołączanie jest pusta lub pominięta, zostaną dołączone wszystkie zestawy, które są ładowane i mają skojarzone pliki PDB. Jeśli zestaw lub składowa jest zgodna z klauzulą w sekcji Wykluczanie , jest ona wykluczona z pokrycia kodu. Sekcja Wykluczanie ma pierwszeństwo przed sekcją Dołączanie: jeśli zestaw jest wymieniony zarówno w obszarze Uwzględnij, jak i Wyklucz, nie zostanie uwzględniony w pokryciu kodu.
Na przykład następujący kod XML wyklucza pojedynczy zestaw, określając jego nazwę:
<ModulePaths>
<Exclude>
<ModulePath>.*Fabrikam.Math.UnitTest.dll</ModulePath>
<!-- Add more ModulePath nodes here. -->
</Exclude>
</ModulePaths>
W poniższym przykładzie określono, że tylko jeden zestaw powinien być uwzględniony w pokryciu kodu:
<ModulePaths>
<Include>
<ModulePath>.*Fabrikam.Math.dll</ModulePath>
<!-- Add more ModulePath nodes here. -->
</Include>
</ModulePaths>
W poniższej tabeli przedstawiono różne sposoby dopasowywania zestawów i elementów członkowskich do włączenia lub wykluczenia z pokrycia kodu.
Element XML | To, co pasuje |
---|---|
ModulePath | Pasuje do zestawów określonych przez nazwę zestawu lub ścieżkę pliku. |
CompanyName | Dopasuje zestawy według atrybutu Company . |
Publickeytoken | Pasuje do podpisanych zestawów za pomocą tokenu klucza publicznego. |
Źródło | Dopasuje elementy według nazwy ścieżki pliku źródłowego, w którym są zdefiniowane. |
Atrybut | Dopasuje elementy, które mają określony atrybut. Określ pełną nazwę atrybutu, na przykład <Attribute>^System\.Diagnostics\.DebuggerHiddenAttribute$</Attribute> .Jeśli wykluczysz CompilerGeneratedAttribute atrybut, kod korzystający z funkcji językowych, takich jak async , await , yield return i automatycznie zaimplementowane właściwości, zostanie wykluczony z analizy pokrycia kodu. Aby wykluczyć prawdziwie wygenerowany kod, wyklucz GeneratedCodeAttribute tylko atrybut . |
Function | Pasuje do procedur, funkcji lub metod według w pełni kwalifikowanej nazwy, w tym listy parametrów. Możesz również dopasować część nazwy przy użyciu wyrażenia regularnego. Przykłady: Fabrikam.Math.LocalMath.SquareRoot(double); (C#)Fabrikam::Math::LocalMath::SquareRoot(double) (C++) |
Formaty pokrycia kodu
Domyślnie pokrycie kodu jest zbierane i zapisywane w .coverage
pliku. Można również zbierać pokrycie przy użyciu innych formatów, takich jak Xml i Cobertura. Różne formaty mogą być przydatne w różnych edytorach i potokach. Można to włączyć w obszarze runsettings, dodając <Format>Cobertura</Format>
lub <Format>Xml</Format>
w sekcji Konfiguracja modułu DataCollector w pliku runsettings. Ten format można wyświetlić w oknie wyników pokrycia kodu w programie Visual Studio Enterprise.
Można również określić różne formaty z wiersza polecenia, określając go w pliku runsettings lub określając go w parametrze. Na przykład wiersz polecenia dotnet używa polecenia dotnet test --collect:"Code Coverage;Format=Cobertura"
. W przypadku programu vstest użyj polecenia vstest.console.exe /collect:"Code Coverage;Format=Cobertura"
. Parametr collect zastąpi format określony w parametrze runsettings.
Instrumentacja statyczna i dynamiczna natywna
W programie Visual Studio 2022 w wersji 17.2 dodaliśmy opcję instrumentowania natywnego binarnego statycznie (na dysku). W poprzednich wersjach obsługiwana była tylko instrumentacja dynamiczna, która często nie była w stanie instrumentować metod. Instrumentacja statyczna natywna jest bardziej stabilna i jest zalecana. Instrumentacja statyczna natywna wymaga włączenia opcji /PROFILE linku dla wszystkich projektów natywnych, dla których potrzebna jest kolekcja pokrycia kodu.
Możesz włączyć natywną instrumentację statyczną, włączając natywną instrumentację statyczną pokrycie kodu w wersji zapoznawczej w obszarze Narzędzia > Opcje > Środowiska > w wersji zapoznawczej.
Możesz również włączyć natywną instrumentację statyczną w ramach ustawień uruchamiania, dodając <EnableStaticNativeInstrumentation>True</EnableStaticNativeInstrumentation>
tag w obszarze <CodeCoverage>
tagu. Użyj tej metody w scenariuszach wiersza polecenia.
Domyślnie instrumentacja dynamiczna natywna jest zawsze włączona. Jeśli zarówno instrumentacja statyczna, jak i dynamiczna jest włączona, program Visual Studio próbuje instrumentować kod C++ statycznie, ale jeśli nie jest to możliwe (na przykład jeśli /PROFILE
opcja linku nie jest włączona), instrumentacja dynamiczna zostanie użyta. Możesz w pełni wyłączyć dynamiczne instrumentację natywną w elementach runsettings, dodając <EnableDynamicNativeInstrumentation>False</EnableDynamicNativeInstrumentation>
element w obszarze <CodeCoverage>
.
Po włączeniu instrumentacji statycznej natywnej natywne pliki binarne będą instrumentowane i zastępowane na dysku przed wykonaniem testu. Oryginalne pliki binarne zostaną przywrócone po wykonaniu testu. Przywracanie oryginalnych plików w ramach ustawień uruchamiania można wyłączyć, dodając <EnableStaticNativeInstrumentationRestore>False</EnableStaticNativeInstrumentationRestore>
pod tagiem <CodeCoverage>
. Może to być szczególnie przydatne w scenariuszach ciągłej integracji.
Po włączeniu instrumentacji statycznej natywnej program Visual Studio będzie wyszukiwać i instrumentować wszystkie natywne pliki binarne w katalogu, w którym znajduje się testowy plik binarny. Możesz określić dodatkowe katalogi, w których mają być przeszukiwane pliki binarne. Poniższy przykład określa, że wszystkie natywne pliki binarne z C:\temp
i jego podkatalogów powinny być instrumentowane z wyjątkiem plików kończących się na Fabrikam.Math.dll
.
<ModulePaths>
<IncludeDirectories>
<Directory Recursive="true">C:\temp</Directory>
</IncludeDirectories>
<Exclude>
<ModulePath>.*Fabrikam.Math.dll</ModulePath>
</Exclude>
</ModulePaths>
Wyrażenia regularne
Węzły dołączania i wykluczania używają wyrażeń regularnych, które nie są takie same jak symbole wieloznaczne. We wszystkich dopasowaniach rozróżniana jest wielkość liter. Niektóre przykłady:
.* pasuje do ciągu dowolnych znaków
\. pasuje do kropki "."
\( \) pasuje do nawiasów "( )"
\\ pasuje do ogranicznika ścieżki pliku "\"
^ pasuje do początku ciągu
$ pasuje do końca ciągu
Poniższy kod XML pokazuje, jak dołączać i wykluczać określone zestawy przy użyciu wyrażeń regularnych:
<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>
Poniższy kod XML przedstawia sposób dołączania i wykluczania określonych funkcji przy użyciu wyrażeń regularnych:
<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>
Ostrzeżenie
Jeśli wystąpi błąd w wyrażeniu regularnym, takim jak niewyrównane lub niedopasowane nawiasy, analiza pokrycia kodu nie zostanie uruchomiona.
Aby uzyskać więcej informacji na temat wyrażeń regularnych, zobacz Używanie wyrażeń regularnych w programie Visual Studio.
Przykładowy plik .runsettings
Skopiuj ten kod i zmodyfikuj go zgodnie z potrzebami.
<?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>