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, jaki zakres kodu jest testowany.
Aby wykluczyć kod testowy z wyników pokrycia kodu i dołączyć tylko kod aplikacji, dodaj atrybut ExcludeFromCodeCoverageAttribute do klasy testowej.
Aby dołączyć 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ń jest plikiem konfiguracji używanym przez narzędzia do testowania jednostkowego. Zaawansowane ustawienia pokrycia kodu są zdefiniowane w pliku .runsettings.
Aby dostosować pokrycie kodu, wykonaj następujące kroki:
Dodaj plik ustawień uruchamiania do rozwiązania. W Eksploratorze rozwiązań , w menu kontekstowym rozwiązania, wybierz Dodaj>Nowy element, a następnie wybierz 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 wykryć plik ustawień uruchamiania w katalogu głównym projektu. W przeciwnym razie na menu testowym wybierz pozycję Skonfiguruj ustawienia uruchamiania, a następnie wybierz pozycję Wybierz plik runsettings dla całego rozwiązania. Aby określić plik ustawień uruchamiania na potrzeby uruchamiania testów z poziomu wiersza polecenia, zobacz Konfigurowanie testów jednostkowych.
Po wybraniu 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ć opcje niestandardowe, odznacz lub wybierz plik w menu Test.
Aby wybrać plik ustawień uruchamiania, w menu testu
wybierz pozycję Wybierz plik ustawień . Aby określić plik ustawień uruchamiania na potrzeby uruchamiania testów z poziomu wiersza polecenia, zobacz Konfigurowanie testów jednostkowych.Po wybraniu Analizuj Pokrycie Koduinformacje 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ę Test, Skonfiguruj ustawienia uruchamianiai odznacz lub zaznacz nazwę pliku.
Ścieżki wyszukiwania symboli
Pokrycie kodu wymaga plików symboli (pliki.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 może być konieczne uwzględnienie referencyjnych zestawów w analizie 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>
Notatka
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 członków
Można dołączać lub wykluczać zestawy lub określone typy i członków z analizy pokrycia kodu. Jeśli sekcja Uwzględnij jest pusta lub pominięta, zostaną uwzględnione wszystkie zgromadzenia, które są ładowane i mają skojarzone pliki PDB. Jeśli zestaw lub składowa pasuje do którejś z klauzul w sekcji Wyklucz, wtedy jest ono wykluczane z pokrycia kodu. Sekcja Wyklucz ma pierwszeństwo przed sekcją Uwzględnij: jeśli zestaw jest wymieniony zarówno w sekcji 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. |
Nazwa firmy | Dopasuje zestawy według atrybutu firmy |
PublicKeyToken | Dopasowuje podpisane zestawy według 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 atrybut CompilerGeneratedAttribute, kod korzystający z funkcji językowych, takich jak async , await , yield return i automatycznie zaimplementowane właściwości zostaną wykluczone z analizy pokrycia kodu. Aby wykluczyć prawdziwie wygenerowany kod, wyklucz tylko atrybut GeneratedCodeAttribute. |
Funkcja | Dopasowuje procedury, funkcje lub metody 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 pliku .coverage
. Można również zbierać dane dotyczące pokrycia przy użyciu innych formatów, takich jak XML i Cobertura. Różne formaty mogą być przydatne w różnych edytorach i przepływach pracy. Można to włączyć w pliku runsettings, dodając <Format>Cobertura</Format>
lub <Format>Xml</Format>
w sekcji konfiguracji 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 dotnet test --collect:"Code Coverage;Format=Cobertura"
. W przypadku programu vstest użyj vstest.console.exe /collect:"Code Coverage;Format=Cobertura"
. Parametr collect zastąpi format określony w parametrze runsettings.
Natywna instrumentacja statyczna i dynamiczna
W wersji 17.2 programu Visual Studio 2022 dodaliśmy opcję statycznego (na dysku) instrumentowania natywnych binariów. 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 natywna statyczna wymaga włączenia opcji linkowania /PROFILE dla wszystkich projektów natywnych, w których zbierasz dane o pokryciu kodu.
Możesz również włączyć natywną instrumentację statyczną w ustawieniach uruchamiania, dodając <EnableStaticNativeInstrumentation>True</EnableStaticNativeInstrumentation>
w obszarze znacznika <CodeCoverage>
. 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 gdy opcja linku /PROFILE
nie jest włączona), zostanie użyta instrumentacja dynamiczna. Dynamiczną instrumentację natywną można w pełni wyłączyć w ustawieniach runsettings, poprzez dodanie <EnableDynamicNativeInstrumentation>False</EnableDynamicNativeInstrumentation>
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>
w tagu <CodeCoverage>
. Może być to szczególnie przydatne w scenariuszach CI.
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ę 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. Wszystkie dopasowania są bez uwzględniania wielkości liter. Oto kilka przykładów:
.* pasuje do ciągu dowolnych znaków
\. pasuje do znaku kropki "."
\( \) odpowiada nawiasom "( )"
\\ 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>
<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>