1. Wprowadzenie
Fucini Coverage Studio zamienia pliki śladu pokrycia, które Twój build już tworzy, w pełnoprawne pokrycie w edytorze — w VS Code i w Visual Studio. Czyta dwadzieścia pięć formatów, normalizuje je do jednego kanonicznego modelu Fucini, deterministycznie scala wiele przebiegów i pokazuje wynik w samym edytorze — marginesy, CodeLens, podpowiedzi i widok Covered Files — więc nie ma osobnej przeglądarki, dla której trzeba opuszczać edytor. Obie edycje dzielą jeden czytnik: ten sam raport daje te same liczby, co do cyfry, w obu. Ten przewodnik jest napisany z perspektywy VS Code; tam, gdzie Visual Studio się różni, ramka In Visual Studio mówi jak.
Zaprojektowano z myślą o procesach bezpieczeństwa funkcjonalnego: pokrycie MC/DC, pokrycie regionów i instancjacji C++, wynik złożony ważony bezpieczeństwem oraz konfigurowalny werdykt COMPLIANT / NON-COMPLIANT zgodny z podejściem IEC 61508, ISO 26262 i DO-178C.
Screenshot pending — add assets/img/marketplace-demo.gif (see SCREENSHOTS.md).2. Instalacja i wymagania
- VS Code ≥ 1.88 — minimalna wersja, którą to rozszerzenie obsługuje — albo Visual Studio 2022 lub 2026, Community, Professional lub Enterprise (zobacz ramkę poniżej).
- Plik śladu pokrycia, który Twój projekt już tworzy (zobacz §4).
Zainstaluj z Marketplace lub z pliku .vsix poprzez Extensions → ⋯ → Install from VSIX…. Rozszerzenie aktywuje się przy starcie i dodaje ikonę Coverage do paska aktywności.
W Visual Studio. Ten sam produkt jest wydawany jako drugie rozszerzenie, Fucini Coverage Studio dla Visual Studio, dla Visual Studio 2022 i 2026 — Community, Professional i Enterprise. Nie korzysta z własnego pokrycia kodu Visual Studio: w Visual Studio 2022 to funkcja Enterprise, więc w Community i Professional to jedyne pokrycie, jakie IDE pokaże. Zainstaluj .vsix, otwierając go — VSIX Installer zapyta, w którym Visual Studio — albo przez Extensions → Manage Extensions; rozszerzenie ładuje się, gdy otwiera się rozwiązanie lub folder. Okno Coverage potrzebuje Microsoft Edge WebView2 Runtime, który Windows 11 i Visual Studio 2026 już mają; znaczniki w edytorze działają bez niego.
3. Szybki start
Chcesz zobaczyć, jak to działa, zanim podepniesz własny projekt? Pobierz projekt demonstracyjny (~6 KB — mały projekt w C z gotowym plikiem lcov.info):
- Rozpakuj go w dowolnym miejscu, a następnie otwórz
coverage-studio-demo.code-workspacew VS Code (File → Open Workspace from File…). - Zainstaluj Fucini Coverage Studio, jeśli jeszcze tego nie zrobiłeś/aś (zob. §2 powyżej).
- Własny plik
.vscode/settings.jsonobszaru roboczego już wskazuje na dołączonycoverage/lcov.info, więc paski pokrycia i widok Covered Files pojawiają się od razu po aktywacji rozszerzenia — krokLoad Coveragenie jest potrzebny. - Chcesz samodzielnie ponownie wygenerować plik śledzenia (np. innym kompilatorem)? Uruchom
scripts/gen-coverage.sh(lub.ps1w Windows) — dostępne cele kompilatorów znajdziesz we własnym plikuREADME.mdobszaru roboczego.
W Visual Studio. Otwórz rozwiązanie albo folder (File → Open → Folder, tak otwiera się projekt CMake) — demo powyżej otwiera się jako folder, a jego .vscode/settings.json jest tam też czytany. Raport w miejscu, które wskazują ustawienia, ładuje się sam, a panel Fucini Coverage okna Output mówi, które pliki; w przeciwnym razie Tools → Coverage Studio → Load Coverage File…, raz — to zostaje zapamiętane. Otwórz plik źródłowy i wybierz Show Coverage in Editor: czerwony to wiersz, który nigdy się nie wykonał, bursztynowy to decyzja podjęta tylko w jedną stronę, a Ctrl+Shift+U, N przechodzi do następnego niepokrytego wiersza. View → Other Windows → Coverage to drzewo z liczbami każdego pliku i jednym wynikiem dla wszystkich, który pasek stanu pokazuje dla przebiegu i dla pliku, w którym jesteś. Tools → Coverage Studio → Getting Started otwiera te kroki jako stronę z przyciskiem do każdego; za pierwszym razem otwiera się sama.
- Wygeneruj plik śledzenia pokrycia standardowym przepływem testów.
- Paleta poleceń (
Ctrl+Shift+P) →Fucini Coverage: Load Coverage. Przy włączonymwatch.enabled(domyślnie), pasujący plik wczytuje się automatycznie. - Otwórz pokryty plik źródłowy: pasek stanu pokazuje jego procent, wypełnia się widok Coverage, najechanie na wiersz pokazuje jego licznik trafień, a przebieg pojawia się w natywnym panelu Test Coverage. Paski na niepokrytych wierszach, mapa cieplna liczby trafień i liczniki
×Nw wierszu są o jedno ustawienie dalej (editorGutter.mode,hitCounts.inline).
Screenshot pending — add assets/img/gutters.png (see SCREENSHOTS.md).4. Generowanie plików śledzenia
Każdy z poniższych jest automatycznie wykrywany przy wczytywaniu:
Kompletne przepisy do skopiowania dla każdego kompilatora — w tym Swift, Rust, Go, Python, .NET, PHP i inne — na stronie Przepisy pokrycia: Swift · Clang · GCC · Rust · Go · Python · Java/Kotlin · JS/TS · .NET · PHP · Ruby.
C / C++ — LLVM (llvm-cov)
clang --coverage -fprofile-instr-generate -fcoverage-mapping test.c -o test
LLVM_PROFILE_FILE=test.profraw ./test
llvm-profdata merge -sparse test.profraw -o test.profdata
llvm-cov export ./test -instr-profile=test.profdata --format=json > coverage.json
llvm-cov JSON to najbogatsze dane wejściowe — oprócz linii, gałęzi i funkcji zawiera regiony, MC/DC i instancjacje szablonów C++.
C / C++ — GCC (gcov → lcov)
gcc --coverage calc.c calc_test.c -o test && ./test
lcov --capture --directory . --output-file lcov.info
# or gcovr --cobertura coverage.xml
# or skip the conversion entirely: gcovr --json coverage.json
JavaScript / TypeScript — Istanbul / nyc
nyc --reporter=json mocha # emits coverage/coverage-final.json
Java — JaCoCo
mvn test # emits target/site/jacoco/jacoco.xml
Ruby — SimpleCov
# .resultset.json (built-in) or coverage.json via the simplecov-json gem
Go
go test ./... -coverprofile=coverage.out # read directly, no conversion
Python — coverage.py
coverage run --branch -m pytest && coverage json # emits coverage.json
PHP — PHPUnit (Clover)
XDEBUG_MODE=coverage phpunit --coverage-clover clover.xml
.NET / C# — Coverlet (OpenCover)
dotnet test /p:CollectCoverage=true /p:CoverletOutputFormat=opencover
| Format | Typowy plik | Dodatkowe metryki |
|---|---|---|
| LCOV | lcov.info | wiersze, gałęzie, funkcje |
| llvm-cov JSON | coverage.json | + regiony, MC/DC, instancjacje |
| Cobertura XML | coverage.xml | wiersze, gałęzie |
| JaCoCo XML | jacoco.xml | wiersze, gałęzie, funkcje |
| Istanbul / nyc | coverage-final.json | instrukcje, gałęzie, funkcje |
| SimpleCov | .resultset.json | wiersze |
| Clover XML | clover.xml | wiersze, gałęzie, funkcje |
| OpenCover XML | coverage.opencover.xml | wiersze, gałęzie, funkcje |
| coverage.py JSON | coverage.json | wiersze, gałęzie |
| gcov / gcovr JSON | coverage.json | wiersze, gałęzie, funkcje |
| Go coverage profile | coverage.out | wiersze |
| SonarQube generic | coverage.xml | wiersze, gałęzie |
| GNATcoverage XML (Ada) | *.xml | wiersze, gałęzie, MC/DC |
| BullseyeCoverage XML | coverage.xml | wiersze, warunek/decyzja |
| Visual Studio | *.coveragexml | wiersze, gałęzie |
| Coveralls JSON | coveralls.json | wiersze, gałęzie |
| Xcode xccov JSON | coverage.json | funkcje i sumy na plik — bez danych na wiersz |
| gcov plain text | *.gcov | wiersze, gałęzie, wywołania funkcji |
| VectorCAST | coverage.xml | wiersze, gałęzie, pary MC/DC, funkcje, wywołania funkcji |
| Testwell CTC++ | *.txt | wiersze, warunek/decyzja |
| Lauterbach TRACE32 | *.xml | instrukcje, decyzje, warunki, MC/DC, funkcje, wywołania, kod obiektowy |
| EMMA XML (Java) | coverage.xml | wiersze |
| UCIS / Aldec UCDB | *.xml | instrukcje, gałęzie decyzji |
| NCover XML | Coverage.xml | wiersze, funkcje |
| dotCover DetailedXML | dotCover.xml | wiersze, funkcje |
| PIT (mutation) | mutations.xml | wynik mutacji — bez pokrycia |
| Stryker (mutation) | mutation-report.json | wynik mutacji — bez pokrycia |
Natywny projekt C++, mierzony z Visual Studio
W Visual Studio. Własne pokrycie projektu C++ w Visual Studio było dostępne tylko w edycji Enterprise, a darmowa wtyczka OpenCppCoverage, która wypełniała tę lukę, została wycofana. Tools → Coverage Studio → Run Native Project with Coverage bierze projekt startowy — .vcxproj — pyta MSBuild, dokąd się kompiluje i na jakim zestawie narzędzi, i mierzy go na jeden z dwóch sposobów. Na zestawie narzędzi ClangCL, z llvm-profdata i llvm-cov z LLVM na maszynie (dostarcza je składnik Visual Studio C++ Clang tools for Windows), kompiluje projekt ponownie do coverage\native\ z -fprofile-instr-generate -fcoverage-mapping, przez plik props, który MSBuild ma zaimportować jako pierwszy — nic w projekcie się nie zmienia — uruchamia program z ustawionym LLVM_PROFILE_FILE, scala profil i eksportuje coverage\native\lcov.info, z dokładnością do regionu. Na każdym innym zestawie narzędzi, z zainstalowanym OpenCppCoverage, kompiluje projekt takim, jaki jest — kompilacja Debug ma pliki PDB — i uruchamia go pod OpenCppCoverage, który zapisuje coverage\native\opencppcoverage.xml. Każde polecenie trafia do panelu Fucini Coverage, a raport jest wczytywany i zapamiętywany jak raport z przebiegu testów. Projekt, którego nie da się zmierzyć, dowiaduje się dlaczego i co zainstalować. MSBuild 17.8 (Visual Studio 2022 17.8) lub nowszy, ze względu na pytanie, które zadaje.
Screenshot pending — add assets/img/vs-native-run.gif (see SCREENSHOTS.md).5. Wczytywanie i wykrywanie
Domyślnie rozszerzenie skanuje od katalogu głównego przestrzeni roboczej. Doprecyzuj to dwoma ustawieniami:
{
"fuciniCoverage.coverageFile.defaultLocation": "${workspaceFolder}/build",
"fuciniCoverage.coverageFile.paths": [
"coverage.json",
"reports/*.info",
"${env:CI_ARTIFACTS}/lcov.info",
"https://ci.example.com/artifacts/latest/coverage.xml"
]
}
- Każdy wpis
pathsjest względny wobecdefaultLocation(lub katalogu głównego przestrzeni roboczej, gdy nieustawione). - Wpis zawierający
*jest przeszukiwany rekurencyjnie; sama nazwa pliku pasuje tylko bezpośrednio w folderze bazowym. - Gdy
pathsjest puste, rozszerzenie szukacoverage.json, następnielcov.info, wczytując to, co znajdzie pierwsze. - Pick Coverage File używa wybranych plików zamiast tych ścieżek — każdy wybór dokłada się do zestawu i wszystkie są scalane — dopóki ich nie usuniesz lub nie zmienisz tych ustawień.
- Zmienne — każde ustawienie ścieżki rozwija
${workspaceFolder},${workspaceFolderBasename},${userHome},${env:NAME},${command:id}i${config:section.key}. Zmienna, której rozszerzenie nie zna, zostaje tak, jak ją zapisano, więc literówka pojawia się w dzienniku wykrywania jako ścieżka, której szukano, zamiast zniknąć.${command:id}najpierw uruchamia to polecenie — tylko w zaufanym obszarze roboczym i najwyżej przez pięć sekund — więc${command:cmake.buildDirectory}podąża za wybranym zestawem CMake. - Wpisy URL — wpis
http(s)://jest pobierany do magazynu rozszerzenia przy każdym wczytaniu i stamtąd wczytywany; widok Coverage podaje adres URL. Każde pobranie jest warunkowe (ETag / Last-Modified), więc niezmieniony artefakt niczego nie ściąga, a gdy pobranie się nie powiedzie, wczytywana jest ostatnia pobrana kopia, z powodem w wyjściu.remote.headersdodaje nagłówkiName: valuez rozwiniętymi zmiennymi,remote.refreshMinutespobiera ponownie według zegara, a fragment#lcov.infowskazuje format, gdy sam adres URL nie kończy się nazwą pliku. - Wzorce ignorowania —
fuciniCoverage.ignoreusuwa całe pliki (dostarczone z zewnątrz, generowane, firm trzecich) z przebiegu podczas wczytywania, więc każdy widok, bramka i eksport liczy bez nich; wynik wczytania mówi, ile pominięto, a wyjście je wymienia. Wzorce dopasowują się do ścieżki względem obszaru roboczego i do ścieżki bezwzględnej, a wzorzec bez/pasuje do nazwy folderu lub pliku na dowolnej głębokości, jak w.gitignore. - Obszary robocze wielokorzeniowe — każdy folder jest wykrywany na własnych warunkach:
defaultLocation,paths,pathRemap,ignore,watch.*iremote.*są czytane per folder, więc obowiązuje własny.vscode/settings.jsonfolderu albo jego wpis w.code-workspace, a${workspaceFolder}we wpisie oznacza własny folder tego wpisu. Pliki śledzenia wszystkich folderów scalają się w jeden przebieg, widok Coverage grupuje pliki według folderu, a folder dodany do obszaru roboczego lub z niego usunięty sam przeładowuje pokrycie. - Przeładowanie po zadaniu —
watch.reloadAfterTaskswymienia zadania (labelz tasks.json albosource: name, tak jak pokazuje je lista Run Task), których zakończenie przeładowuje pokrycie, niezależnie od tego, czywatch.enabledjest włączone — dla kompilacji, za którymi obserwator nie nadąża. Bezwzględny wpispathspoza obszarem roboczym jest również odpytywany, więc plik, który się tam pojawi, zostaje wczytany. - Postęp, który można anulować — wczytanie dziesięciu lub więcej plików śledzenia, albo 8 MB lub więcej takich plików, działa pod powiadomieniem o postępie z przyciskiem Anuluj, które podaje czytany plik i etap; mniejsze tylko kręci paskiem stanu. Anulowanie zostawia poprzedni przebieg wczytany i mówi o tym.
Od 1.2026.6 wpis bezwzględny też może zawierać symbol wieloznaczny: ${workspaceFolder}/build/coverage-merged/*.lcov.info wczytuje każdy taki plik w tym folderze, a ** oznacza dowolną głębokość. Foldery przed pierwszym symbolem wieloznacznym to miejsce, w którym szuka, i są obserwowane, więc raport, który kompilacja tam zapisze, wczytuje się sam. Edycja dla Visual Studio czyta taki wpis tak samo, a od 1.2026.5 względny symbol wieloznaczny jest tam również przeszukiwany na dowolnej głębokości, jak zawsze było tutaj.
Gdy nie skonfigurowano paths, wczytywany jest pierwszy raport o powszechnie znanej nazwie znaleziony w folderze bazowym. Najpierw cztery nazwy, których rozszerzenie szukało zawsze — coverage.json, lcov.info, coverage.out, clover.xml — następnie, od wersji 0.2026.83, jacoco.xml, coverage.xml, cobertura.xml, coverage.cobertura.xml, coverage.opencover.xml i coverage-final.json, a potem miejsca, do których zapisują konfiguracje domyślne: coverage/ (nyc, Jest, vitest, PHPUnit, SimpleCov), target/site/jacoco/jacoco.xml (Maven), build/reports/jacoco/test/jacocoTestReport.xml (Gradle) oraz TestResults/*/coverage.cobertura.xml (dotnet test). Dzięki temu projekt Java lub .NET pokazuje swoje pokrycie już przy pierwszym otwarciu, tak jak zawsze działo się to w projekcie lcov.
Od 1.2026.3 rozwiązanie .NET potrzebuje jeszcze mniej: folder TestResults/<run>/ każdego projektu testowego jest wśród dobrze znanych miejsc, nie tylko folder samego obszaru roboczego, a <user>_<machine>_<date>.cobertura.xml kolektora Microsoftu jest znajdowany obok coverage.cobertura.xml Coverleta — więc rozwiązanie, którego testy uruchomiono w Test Explorer Visual Studio, pokazuje swoje pokrycie przy pierwszym otwarciu, każdy folder uruchomienia jest wczytywany, a scalanie zachowuje dla każdego pliku wynik najnowszego uruchomienia. A fuciniCoverage.ignore.generated, domyślnie włączone, pomija pliki projektanta i generowane — *.Designer.cs, *.g.cs, *.generated.cs, *.razor.g.cs, AssemblyInfo, globalne usingi, Migrations/ i obj/ — w każdej sumie, stronie i eksporcie, zanim zostanie zastosowane ignore, więc generowana tabela, której nikt nie testuje, nie kosztuje rozwiązania jego progu.
W Visual Studio: pokrycie po każdym uruchomieniu testów. Uruchamiaj testy tak jak zawsze. Tools → Coverage Studio → Collect Coverage in Test Explorer… kładzie obok rozwiązania jeden .runsettings z kolektorem Cobertura Microsoftu. Visual Studio podejmuje go, gdy Tools → Options → Test → Auto detect runsettings files jest włączone; w przeciwnym razie wybierz go raz w Test → Configure Run Settings. Od tej pory każde uruchomienie zapisuje raport pod projektem testowym, a obserwacja rozwiązania wczytuje go w chwili, gdy się pojawi, scalony ze wszystkim, co wskazują ustawienia — jednakowo z Test Explorer, z terminala czy ze skryptu. Nic nie podpina się pod Test Explorer, więc Visual Studio 2026 i Microsoft.Testing.Platform działają takie, jakie są. Run Tests with Coverage to polecenie VS Code: rozpoznaje dotnet test, vitest, jest, pytest, go, cargo, maven, gradle, phpunit i ctest, uruchamia testy z włączonym pokryciem w oknie Output i wczytuje to, co zapisały; projekt testowy bez coverlet.collector jest uruchamiany z kolektorem dostarczanym z testowym SDK, a testRun.skipWhenTestsFail zachowuje na ekranie ostatnie dobre pokrycie, gdy uruchomienie kończy się na czerwono.
Artefakt CI za tokenem, sprawdzany ponownie co kwadrans — token pozostaje w środowisku, nigdy w settings.json:
{
"fuciniCoverage.coverageFile.paths": [
"https://ci.example.com/api/builds/latest/artifacts/coverage#lcov.info"
],
"fuciniCoverage.remote.headers": ["Authorization: Bearer ${env:CI_TOKEN}"],
"fuciniCoverage.remote.refreshMinutes": 15
}
Screenshot pending — add assets/img/remote-tracefile.png (see SCREENSHOTS.md).Przeładowanie jest ciche celowo — okno dialogowe po każdej kompilacji to pytanie z jedną odpowiedzią. Cicha nie jest ikona Coverage: dopóki widok nie jest przed Tobą, nosi liczbę plików śledzenia odczytanych ponownie, a jej podpowiedź je wymienia. Otwórz widok, a licznik znika.
Screenshot pending — add assets/img/coverage-badge.gif (see SCREENSHOTS.md).Pliki, które nigdy nie powinny się liczyć, cokolwiek mówi o nich plik śledzenia:
{
"fuciniCoverage.ignore": ["vendor/**", "**/*.generated.ts", "build/**"]
}
Przeładowanie po zakończeniu zadania testowego, dla kompilacji, za którą obserwator plików nie nadąża — przebieg, który podmienia dowiązane symbolicznie drzewo wyjściowe, raport na udziale sieciowym, krok pokrycia, który dodatkowo przetwarza swój plik:
{
"fuciniCoverage.watch.reloadAfterTasks": ["npm: test", "coverage-report"]
}
6. Łączenie przebiegów
Każdy istniejący wpis paths jest wczytywany i scalany w jedno uruchomienie. Scalanie jest deterministyczne — wynik nie zależy od kolejności wczytywania — a plik zmierzony przez więcej niż jeden plik śledzenia bierze swoje liczby z tego o najnowszym czasie modyfikacji na dysku: własne ponowne uruchomienie modułu zastępuje to, co mówiło o nim szersze, starsze uruchomienie, zamiast się do niego dodawać. Widok Pokrycia pokazuje, co to zrobiło: każdy wiersz pliku podaje plik śledzenia, z którego pochodzą jego liczby, plakietka ma obrys tam, gdzie te liczby zastąpiły starszy raport, każdy wiersz pliku śledzenia nad drzewem liczy, ile jego plików zostało zastąpionych lub zastąpiło inne, a kliknięcie wiersza pliku śledzenia podświetla jego pliki w drzewie aż do ponownego kliknięcia (coverageView.mergedMarks wyłącza obrys i podświetlenie).
Połączony przebieg może zawierać więcej niż sześć klasycznych metryk, każdą z raportu, który ją mierzy: wywołania funkcji, kod obiektowy i wynik mutacyjny obok wierszy, funkcji, regionów, gałęzi, MC/DC i instancjacji. Widok Coverage pokazuje kolumnę dla każdej metryki, którą przebieg zawiera — i żadnej dla tej, której nie zawiera — uporządkowane według wagi, jaką każda metryka ma w Twoim wyniku, od najcięższej, przy dowolnej szerokości — to, co się nie mieści, przewija się w bok, zamiast znikać. Po przeciągnięciu do dolnego panelu widok staje się tabelą. Karty paska stanu, raport HTML oraz eksporty CSV i Markdown stosują tę samą zasadę: to, co raport zawiera, jest pokazywane, a to, czego nie zawiera, jest pomijane, zamiast być drukowane jako zero.
Screenshot pending — add assets/img/coverage-view-editor.png (see SCREENSHOTS.md).
Screenshot pending — add assets/img/coverage-view-columns.png (see SCREENSHOTS.md).
Screenshot pending — add assets/img/workspace-overview.gif (see SCREENSHOTS.md).
Screenshot pending — add assets/img/vs-workspace-overview.gif (see SCREENSHOTS.md).Z którego raportu pochodzi plik
Gdy kilka wczytanych raportów mierzy ten sam plik, najnowszy wygrywa go w całości — słusznie, gdy własne ponowne uruchomienie modułu zastępuje to, co mówiło starsze, szersze uruchomienie. Niesłusznie, gdy raporty mierzą ten sam kod celowo: wtedy edytor przeskakuje między nimi przy każdej kompilacji, a każdy opowiada tylko część historii. coverageFile.sources mówi, co zrobić zamiast tego, osobno dla każdego pliku. Przydaje się w trzech sytuacjach:
- Jeden raport jest lepszy.
coverage.jsonz llvm-cov zawiera MC/DC, agcov.infoz GCC dla tej samej kompilacji tylko wiersze i gałęzie: wybierzcoverage.json, a drugi zostaw dla tych kilku plików, które kompiluje tylko GCC. - Kilka zestawów testów jednej kompilacji. Testy jednostkowe, testy integracyjne i hardware-in-the-loop zapisują każdy własny raport; każdy z osobna pomija wiersze, które wykonały pozostałe. Połącz, union: wiersz jest pokryty tam, gdzie wykonał go którykolwiek raport, a liczniki się sumują.
- Jedna baza kodu, dwa kompilatory. Te same źródła skompilowane przez clang i przez GCC przechodzą różnymi ścieżkami przez kod zależny od toolchainu — tu intrinsic, tam przenośna alternatywa — i każdy raport twierdzi, że druga połowa nigdy się nie wykonała. Połącz, agree: wiersz jest pokryty tylko tam, gdzie wykonał go każdy raport, który go mierzy, a wiersze, co do których raporty się różnią, są oznaczone kolorem morskim. Właśnie to pytanie zadaje kontrola między kompilatorami: co naprawdę sprawdziła każda kompilacja, którą dostarczam?
Reguły rzadko pisze się ręcznie. Kliknij plik prawym przyciskiem w widoku Pokrycia i wybierz Choose Coverage Source... (albo uruchom Choose Coverage Source for This File... na otwartym pliku): lista zawiera każdy raport, który mierzy plik, każdy z własnymi wierszami, gałęziami i MC/DC, a potem Combine them — agree i Combine them — union; wybierz jedną pozycję i wskaż, czy dotyczy pliku, jego folderu czy wzorca. Clear Coverage Source for This File... z powrotem usuwa regułę. W ustawieniach każda reguła to wzorzec glob dla plików, wzorzec glob dla raportu (wzorzec bez / pasuje do nazwy pliku raportu, {a,b} wskazuje kilka) oraz, do łączenia, "combine": "agree" lub "union". Rozstrzyga pierwsza reguła, której pliki pasują i której raport mierzy dany plik; pliku mierzonego tylko przez jeden raport nigdy się temu raportowi nie odbiera. Gałęzie, MC/DC i regiony połączonego pliku pochodzą z raportu, który ma ich najwięcej. coverageFile.mergeStrategy: "order" rozstrzyga pliki, których nie dotyczy żadna reguła, według kolejności w coverageFile.paths zamiast według czasów.
{
"fuciniCoverage.coverageFile.paths": ["clang.json", "gcc/bits.gcov.json.gz"],
"fuciniCoverage.coverageFile.sources": [
{ "files": "src/**", "report": "{clang.json,bits.gcov.json.gz}", "combine": "agree" }
]
}
Co widać: wiersz pliku w widoku Pokrycia podaje raport, z którego pochodzą jego liczby, a po połączeniu każdy raport i tryb z ≠ n dla spornych wierszy. Margines edytora i Annotated Source oznaczają te wiersze kolorem morskim i podają, który raport wykonał je ile razy. Podpowiedź paska stanu podaje źródło otwartego pliku, a dla całego przebiegu obowiązujące reguły i sposób rozstrzygnięcia pozostałych plików. samples/c-cross-check z demo to przypadek dwóch kompilatorów, gotowy do otwarcia. Visual Studio też to wszystko potrafi: Choose Coverage Source... na wierszu widoku Pokrycia oraz Choose i Clear Coverage Source for This File... w Tools > Coverage Studio.
Wybieranie i łączenie źródeł należy do płatnych planów. W Community najnowszy raport wygrywa każdy plik, tak jak bez reguły, a reguła w ustawieniach jest wskazywana jako nieużywana, a nie po cichu pomijana.

bits.c z widoku Pokrycia — raport clang, raport GCC albo oba połączone.


bits.c, clang i GCC połączone przez agree — wiersz pokazuje ≠ 4, a cztery wiersze, które wykonała tylko jedna kompilacja, są w kolorze morskim.
bits.c osiąga 100% swoich wierszy — a wiersze, co do których kompilacje się różnią, pozostają w kolorze morskim.


7. Przemapowanie ścieżek
CI często zapisuje bezwzględne ścieżki maszyny budującej, które nie istnieją na Twojej stacji roboczej. Przepisz je za pomocą uporządkowanych reguł:
{
"fuciniCoverage.pathRemap": [
{ "from": "/builds/ci/project", "to": "${workspaceFolder}" },
{ "from": "\\\\", "to": "/" }
]
}
Reguły są stosowane w kolejności; pierwsze dopasowanie wygrywa dla danego prefiksu. Użyj tego, aby zniwelować różnice separatorów Windows/Unix lub zmapować ścieżkę kontenera na Twój checkout.
Rzadko musisz pisać regułę samodzielnie. Najczęstsze „wczytało się, ale nic się nie podświetla” to plik śledzenia, którego ścieżki pochodzą z kontenera lub checkoutu CI (/build/src/a.c, /home/runner/work/repo/repo/src/a.c, C:\agent\_work\1\s\src\a.c), podczas gdy obszar roboczy ma src/a.c. Gdy po wczytaniu zostają niedopasowane pliki, rozszerzenie wyszukuje ich nazwy w obszarze roboczym, wywodzi regułę prefiksu, która wyjaśnia ich najwięcej, zapisuje ją w dzienniku jako [FUCINI_REMAP_002], a wynik wczytania oferuje Apply Suggested Remap — jedno kliknięcie dopisuje regułę do fuciniCoverage.pathRemap i przeładowuje. Suggest Path Remap Rule uruchamia tę samą analizę na żądanie z palety. Bez kliknięcia nic nie jest zapisywane.
to może używać ${workspaceRoot}, które oznacza folder obszaru roboczego, w którym leży plik śledzenia; w obszarze roboczym wielokorzeniowym próbuje najpierw tego folderu, a potem każdego innego, w którym plik się okaże być. Same reguły są czytane per folder, więc każdy korzeń obszaru wielokorzeniowego może mieć własne.
8. Pokrycie w edytorze
- Marginesy i linijka — domyślnie własny margines edytora pokazuje tylko ustalenia: paski MC/DC, trójkąty „od ostatniego przebiegu”, kropki edytowanych wierszy.
editorGutter.modedodaje paski tylko na niepokrytych wierszach albo mapę cieplną liczby trafień (poniżej); kolorowy widok całego pliku to Annotated Source. - CodeLens funkcji — % pokrycia nad każdą funkcją; kliknij, aby przejść do jej pierwszej niepokrytej linii. Przełącz za pomocą
codeLens.enabled. - Podpowiedzi po najechaniu na gałąź i MC/DC — najedź na linię decyzyjną, aby zobaczyć liczby wzięte/niewzięte na gałąź oraz tabelę wektora per warunek. Włącz kolorowy pasek marginesu za pomocą
mcdcGutter.enabled. - Ostrzeżenia o martwym kodzie — funkcje z mierzalnymi liniami i zerowym pokryciem są oznaczane w panelu Problems (
deadCode.enabled). - Next / Previous Uncovered — przeskakiwanie między lukami.
- Pasek stanu — element
$(dashboard) NN%dla całego przebiegu i element per plik, oba kolorowane według wyniku złożonego; najedź kursorem, aby zobaczyć pełną tabelę metryk. - Odznaki w Eksploratorze — odznaki pokrycia per plik i per folder, z podziałem na metryki po najechaniu. Domyślnie wyłączone: włącz je przez
explorerBadges.enabled. - Od ostatniego przebiegu — czerwony trójkąt na każdym wierszu wykonanym w poprzednim przebiegu, a nie w tym, zielony w odwrotnym przypadku, z linijką przeglądu i liczbą trafień po najechaniu.
- Edytowane bufory — każde oznaczenie, podpowiedź i CodeLens przesuwa się z tekstem podczas edycji i znika z przepisanego wiersza, gdzie szara kropka mówi dlaczego.
- Liczniki trafień w wierszu —
hitCounts.inlinedopisuje×12za każdym wierszem, w którym zaczyna się instrukcja, łącznie z×0: liczbę, która zawsze była w podpowiedzi, bez najeżdżania. Toggle Inline Hit Counts ją przełącza; menu paska stanu oferuje ją jako Pokaż lub Ukryj, zależnie od tego, co ma zastosowanie. - Wpisy w Problems per wiersz —
problems.perLinestawia diagnostykę Information, z falistą linią w edytorze, na każdym ciągłym bloku wierszy, które nigdy się nie wykonały, w otwartym dokumencie (martwa funkcja o czterdziestu wierszach to jeden wpis, nie czterdzieści), a jakouncoveredAndPartialna każdym wierszu, którego gałęzi nigdy nie wzięto. Wpisy podążają za swoimi wierszami podczas edycji i znikają, gdy dokument zostanie zamknięty; wpis per plik zaproblems.enabledpozostaje bez zmian. - Podbarwienie wiersza —
lineHighlightumieszcza półprzezroczyste tło za samymi wierszami, dla tego, co oznacza margines (uncoveredalboheatmap, także dla wierszy wykonanych). Osobne ustawienie, aby margines mógł zostać czysty, gdy luki są podbarwione, albo odwrotnie. - Linijka podglądu —
overviewRulerdecyduje o pasku na pasku przewijania niezależnie od marginesu:follow(razem ze słupkami, jak dotąd),uncovered(zawsze, więc margines może być wyłączony, a pasek przewijania nadal pokazuje mapę luk) albooff. - Który plik śledzenia pokrył wiersz — przy kilku scalonych raportach dymek z liczbą wykonań kończy się słowami Pokryte przez: i każdym raportem, który pokrył ten wiersz, łącznie z nazwą zestawu z
TN:w lcov; kliknięcie wiersza pliku śledzenia w widoku Coverage podświetla wiersze, które on wniósł, w każdym otwartym edytorze.
Screenshot pending — add assets/img/codelens-hover.png (see SCREENSHOTS.md).
Screenshot pending — add assets/img/codelens-crap.png (see SCREENSHOTS.md).
Screenshot pending — add assets/img/jump-between-gaps.gif (see SCREENSHOTS.md).
Screenshot pending — add assets/img/explorer-badges.png (see SCREENSHOTS.md).Tryby marginesu edytora
editorGutter.mode decyduje, co własny margines edytora pokazuje o pokryciu, ponad ustaleniami, które pokazuje zawsze. off (domyślnie) to tylko one. uncovered stawia pasek na każdym wierszu, który nigdy się nie wykonał, bursztynowy na każdym wierszu z gałęzią, której nigdy nie wzięto, i nic na wierszach pokrytych, więc zielona ściana nie zasłania trzech czerwonych. coverage dodaje zielony pasek na każdym pokrytym wierszu, więc cały plik czyta się na czerwono, bursztynowo i zielono w kolorach skali kolorów. heatmap dodaje zamiast tego ciepły odcień na każdym wykonanym wierszu, tym gorętszy, im częściej się wykonał — pokazuje, jak często wiersz się wykonał, a nie czy jest pokryty, więc plik ze 100% jest tam od żółtego do brązowego, nigdy zielony. Choose Editor Gutter Mode... wybiera tryb z palety lub z menu paska stanu; przycisk trybu po prawej stronie paska stanu albo Alt+G jednym naciśnięciem przechodzi do następnego (statusBar.showModeToggle ukrywa przycisk). Oba zapisują ustawienie. Przykład włącza razem paski na niepokrytych wierszach i liczniki w wierszu:
{
"fuciniCoverage.editorGutter.mode": "uncovered",
"fuciniCoverage.hitCounts.inline": true
}
Screenshot pending — add assets/img/gutters.png (see SCREENSHOTS.md).
coverage — zielony tam, gdzie wiersz wykonał się w całości, bursztynowy tam, gdzie gałęzi nigdy nie wzięto, czerwony tam, gdzie nic się nie wykonało. Element pliku na pasku stanu podaje raport, z którego pochodzą jego liczby; przycisk trybu obok pokazuje Coverage.
Alt+G cztery razy — heatmap, off, uncovered i z powrotem coverage.
Quote.cs.Mapa cieplna jest względna w obrębie pliku. Odcień wiersza porównuje jego licznik z najgorętszym wierszem tego samego pliku, w skali logarytmicznej, w pięciu stopniach — dzięki temu ciało pętli wykonane tysiąc razy i funkcja wykonana dwa razy są jednakowo widoczne, zamiast aby jedno przytłaczało drugie, a plik, w którym wszystko wykonało się dokładnie raz, jest jednolicie ciepły, a nie jednolicie blady. W ciemnym motywie skala biegnie od przygaszonej oliwki do żywego pomarańczu, w jasnym od bladej żółci do brązu: w obu przypadkach więcej koloru oznacza więcej wykonań, a czerwień pozostaje zarezerwowana dla wierszy, które nigdy się nie wykonały. lineHighlight: "heatmap" umieszcza te same odcienie za kodem jako tło, a hitCounts.inline zapisuje dokładny licznik za wierszem.
{
"fuciniCoverage.editorGutter.mode": "heatmap",
"fuciniCoverage.lineHighlight": "heatmap",
"fuciniCoverage.hitCounts.inline": true
}
Screenshot pending — add assets/img/heatmap-dark.png (see SCREENSHOTS.md).
Screenshot pending — add assets/img/heatmap-light.png (see SCREENSHOTS.md).
Screenshot pending — add assets/img/heatmap.gif (see SCREENSHOTS.md).Kolory należą do Ciebie. colorScale.lowColor, midColor i highColor malują czerwień, bursztyn i zieleń na marginesie, w podbarwieniach i w każdym procencie; heatmap.colors i heatmap.colorsDark przechowują pięć odcieni mapy cieplnej dla jasnego i ciemnego motywu, od wiersza wykonanego najrzadziej do wykonanego najczęściej. Strona ustawień pokazuje wynik, zanim cokolwiek zostanie zapisane: w sekcji Colour scale podgląd pozostaje widoczny, gdy wiersze przewijają się obok — gradient z dwoma punktami zwrotnymi, kilka procentów w ich kolorach oraz mały jasny i mały ciemny edytor pomalowane w trybie coverage i mapą cieplną — i odświeża się, gdy tylko zostanie wybrany kolor.
{
"fuciniCoverage.heatmap.colors": ["#e3f2fd", "#90caf9", "#42a5f5", "#1e88e5", "#0d47a1"]
}


Część wiersza, która nigdy się nie wykonała
Wiersz jest pokryty albo nie, a prawda często leży pośrodku: return x > hi ? hi : x; się wykonał, ale jego ramię hi — nigdy. Przy włączonym lineHighlight nigdy niewykonana część wykonanego wiersza jest w edytorze podbarwiona, dla każdego formatu, który zawiera zakresy kolumn (llvm-cov, Istanbul, Go, dotnet-coverage) — to te same zakresy, które oznacza Annotated Source. Tylko w wierszach, które się wykonały: wiersz, który nigdy się nie wykonał, jest już oznaczony w całości. Szablon C++ liczy się jako wykonany tam, gdzie wykonała go dowolna instancjacja; to, co zrobiła każda z instancjacji, pokazuje metryka instancjacji.
Screenshot pending — add assets/img/partial-line.png (see SCREENSHOTS.md).Które testy wykonały ten wiersz
Niektóre raporty mówią nie tylko, że wiersz się wykonał, ale też które testy go wykonały: coverage.py zapisany poleceniem coverage json --show-contexts z ustawieniem dynamic_context = test_function w .coveragerc, OpenCover zebrany z opcją -coverbytest oraz plik śledzenia lcov zapisany po jednej sekcji na test (TN:), którego sekcje są sumowane w jeden rekord z testami przy każdym wierszu. Najedź kursorem na początek wiersza, tam gdzie widnieje liczba trafień, a testy zostaną wymienione — skrócone do klasy i metody, pierwszych pięć z nazwy, a pozostałe jako liczba; CodeLens funkcji mówi, ile testów ją wykonało. Show Tests That Ran This Line — z Command Palette, menu kontekstowego edytora, w Visual Studio z Tools → Coverage Studio lub Ctrl+Shift+U, T — wypisuje je, najaktywniejsze najpierw, i otwiera wybrany tam, gdzie jest zapisany w obszarze roboczym. Przebieg dotnet test nie potrafi powiedzieć, który test co wykonał; ustaw testRun.perTest, a Run Tests with Coverage wypisze klasy testowe i uruchomi je po jednej, oznaczając każdy raport jego klasą, aby podpowiedź, CodeLens i polecenie mogły odpowiedzieć także dla .NET. Informacja ta jest przechowywana dla każdego pliku osobno, więc przetrwa scalenie z raportem, który o testach nic nie wie.
{
"fuciniCoverage.testRun.perTest": true
}
# .coveragerc
[run]
dynamic_context = test_function
coverage run -m pytest && coverage json --show-contexts
Screenshot pending — add assets/img/tests-per-line.gif (see SCREENSHOTS.md).
Screenshot pending — add assets/img/tests-for-line.gif (see SCREENSHOTS.md).
Quote.cs — test, który go wykonał, i Go to Test, który go otwiera.Przeszedł czy nie, na oznaczeniach
Pokryty wiersz wygląda tak samo, niezależnie od tego, czy jego test przeszedł. Tam, gdzie raport mówi, które testy wykonały wiersz, a plik wyników runnera mówi, jak się zakończyły, wiersz wykonany przez test, który nie przeszedł, dostaje czerwony pasek na początku i kreskę na linijce przeglądu; podpowiedź po najechaniu wymienia testy, które nie przeszły, a Show Tests That Ran This Line dopisuje przy każdym z nich nie przeszedł. Gdy test jest czerwony, szukać trzeba w kodzie, przez który przeszedł. Wyniki są czytane przy każdym wczytaniu z folderu każdego raportu — dowolny .trx oraz nazwy, których używają narzędzia zapisujące format JUnit (TEST-*.xml, junit*.xml, test-results*.xml) — oraz z testResults.paths, jako ścieżki lub globy względem folderu. Run Tests with Coverage prosi dotnet test o test-results.trx obok raportu, więc przy włączonym testRun.perTest niczego nie trzeba konfigurować. testResults.enabled wyłącza to czytanie.
{
"fuciniCoverage.testResults.paths": ["build/test-results/**/*.xml", "reports/junit.xml"]
}
Screenshot pending — add assets/img/pass-fail.gif (see SCREENSHOTS.md).
Screenshot pending — add assets/img/vs-pass-fail.gif (see SCREENSHOTS.md).Testy, których dotyka zmiana
Pełny przebieg odpowiada powoli na to, na co Run Tests Affected by My Changes… odpowiada od razu: które ze wszystkich testów przeszły przez kod, który właśnie zmieniłem? Git jest pytany o diff drzewa roboczego względem testImpact.baseRef — domyślnie HEAD, czyli to, co jeszcze nie zostało zatwierdzone; origin/main dla wszystkiego, co zmienia gałąź — i wypisywane są testy, które wykonały zmieniony wiersz, najpierw ten, który wykonał największą część zmiany. Wybranie testu otwiera go. Tam, gdzie raporty pochodzą z przebiegu per test (testRun.perTest), pierwsza pozycja uruchamia tylko te testy, każdą klasę do jej własnego raportu, więc raporty wszystkich pozostałych klas zostają, a sumy pozostają sumami całego zestawu. Test, który wykonał tylko wiersze poniżej wstawienia lub usunięcia, też jest wypisywany: inaczej jego raport wskazywałby niewłaściwe wiersze.
Screenshot pending — add assets/img/test-impact.gif (see SCREENSHOTS.md).
Screenshot pending — add assets/img/vs-test-impact.gif (see SCREENSHOTS.md).Najmniej testów, które nadal wykonują każdy wiersz
Show Minimal Test Set… odpowiada na dwa pytania na podstawie tych samych wierszy per test: które nieliczne testy nadal wykonałyby każdy wiersz wykonywany przez zestaw — na szybki przebieg przed commitem — i które testy nie wykonują żadnego wiersza, którego nie wykonuje już inny. Najpierw idą wybrane testy, każdy z wierszami, które dodaje, i wierszami, które wykonuje tylko on; potem reszta, każdy oznaczony jako niedodający niczego. Wybór jest zachłanny — test, który wykonuje najwięcej, potem ten, który najwięcej do niego dodaje — więc jest bliski najmniejszego zbioru i za każdym razem taki sam. Zbędny pod względem wierszy nie znaczy zbędny pod względem tego, co test sprawdza: test, który nie dodaje żadnego wiersza, może nadal być jedynym, który sprawdza wartość w tych wierszach. Lista mówi, gdzie patrzeć przy przycinaniu zestawu, nigdy — co usunąć.
Screenshot pending — add assets/img/minimal-test-set.png (see SCREENSHOTS.md).
Screenshot pending — add assets/img/vs-minimal-test-set.png (see SCREENSHOTS.md).Uruchom ten test, z pokryciem
Ustaw kursor w teście i uruchom Run This Test with Coverage — z Command Palette, menu kontekstowego edytora, w Visual Studio z Tools → Coverage Studio lub Ctrl+Shift+U, R — a tylko ten test uruchomi się z włączonym pokryciem: metoda testowa, w której jest kursor, albo klasa testowa lub blok describe, gdy stoi między metodami, albo plik, gdy jest nad każdą klasą. To, co jest pod kursorem, odczytywane jest z tekstu, więc działa dla C#, VB i F# ([Fact], [Test], [TestMethod] i podobne), JavaScriptu i TypeScriptu (it, test, describe) oraz Pythona (def test_…), niezależnie od zainstalowanej usługi językowej. Przepis folderu jest zawężany do niego — dotnet test --filter "FullyQualifiedName~…", jest lub vitest <file> -t "…", identyfikator węzła pytest — a to, co zapisał, jest wczytywane jak każdy przebieg; runner, którego nie da się zawęzić, mówi o tym, a Run Tests with Coverage uruchamia wszystkie.
Screenshot pending — add assets/img/run-this-test.gif (see SCREENSHOTS.md).
[Fact] — przebieg na liście Tracefiles, wiersze nad metodami mówią, że kod wykonał jeden test.Go i Rust. W pliku Go funkcja func TestXxx (albo Fuzz…, Example…), w której stoi kursor, uruchamia się sama, we własnym pakiecie i po dokładnej nazwie — go test ./pkg/calc -run "^TestTotal$" — a poza testem uruchamia się pakiet pliku. W pliku Rust funkcja #[test] uruchamia się po swojej ścieżce w crate z --exact; gdy kursor stoi w mod i poza jakimkolwiek testem, uruchamiają się testy tego modułu; test integracyjny w tests/ uruchamia się we własnym pliku binarnym (--test api). Runner dostaje wyłącznie pliki swojego języka: plik TypeScript w folderze Go dostaje jedno zdanie, a nie przebieg niczego.
Pokrycie po każdym zapisie
Przy włączonym testRun.onSave zapisanie pliku źródłowego uruchamia testy, które go pokrywają, z pokryciem, chwilę po zapisie, a margines nadąża. Dla rozwiązania .NET projekt zapisanego pliku jest znajdowany przez graf .csproj i uruchamiane są tylko projekty testowe, które się do niego odwołują — bezpośrednio lub przez inne projekty — po jednym dotnet test <project> każdy; każdy inny runner uruchamia cały swój przepis; plik, którego nie posiada żaden projekt i nie mierzy żaden raport, nie uruchamia niczego. Kilka zapisów z rzędu to jeden przebieg, a trwający już przebieg nie jest przerywany. Reszta jest taka, jak robi to Run Tests with Coverage: terminal, panel Output, wczytany raport. Domyślnie wyłączone — to nawyk do wybrania, a nie domyślne ustawienie do odkrycia.
{
"fuciniCoverage.testRun.onSave": true
}
Screenshot pending — add assets/img/coverage-on-save.gif (see SCREENSHOTS.md).
testRun.onSave włączone — Quote.cs zapisany, testy uruchamiają się same, wiersz nad metodą się zmienia.Sama aplikacja, z pokryciem
Przebieg testów mówi, dokąd docierają testy. To, dokąd dociera człowiek — przeklikując ekrany przed wydaniem, odtwarzając kroki klienta — to też pokrycie, a Run App with Coverage… je zbiera. Aplikacja .NET z folderu — Exe, WinExe, projekt webowy lub worker, nigdy projekt testowy; do wyboru, gdy jest ich kilka — jest uruchamiana pod dotnet-coverage Microsoftu we własnej konsoli, tak aby w aplikacji konsolowej dało się pisać, i działa, dopóki jej nie zamkniesz. To, co w niej odwiedzisz, jest potem wczytywane jak każdy przebieg, a w sesji pokrycia jest dodawane do tego, co wykonały testy. Sposób zakończenia aplikacji nie obciąża przebiegu. Narzędzie jest potrzebne raz: dotnet tool install --global dotnet-coverage.
Screenshot pending — add assets/img/run-app.gif (see SCREENSHOTS.md).
Screenshot pending — add assets/img/vs-run-app.gif (see SCREENSHOTS.md).Mutanty i miejsca, w których się znajdują
Narzędzie do testów mutacyjnych — PIT dla Javy, Stryker dla JavaScriptu, C# i Scali, Mull dla C i C++ — wprowadza w kodzie drobne zmiany i dla każdej z nich uruchamia testy. Zmiana, której nie zauważa żaden test, to mutant, który przeżył: kod się wykonał, ale nic nie sprawdziło, co zrobił. Wynik mutacyjny mówi, ile mutantów wykryto; od wersji 0.2026.83 edytor mówi, gdzie są pozostałe. Wiersz z takim mutantem ma za sobą adnotację (⚑ 2 mutants survived), zmieniony tekst jest podkreślony, jeśli raport podaje, o który tekst chodziło (robią to Stryker i Mull), na linijce przeglądu pojawia się pasek, a po najechaniu kursorem widać, co zostało zmienione, ile testów wykonało ten kod, a w przypadku mutantów wykrytych — który test je wykrył.
Screenshot pending — add assets/img/mutant-hover.png (see SCREENSHOTS.md).Przeżył oznacza, że testy wykonały zmieniony kod i wszystkie zakończyły się powodzeniem. Nietestowany (w raporcie: no coverage) oznacza, że żaden test w ogóle nie wykonuje tego kodu, więc nic nie mogło zmiany zauważyć. Mutanty wykryte są zliczane w podpowiedzi po najechaniu i nigdy nie są oznaczane, a mutanty, które nigdy nie były uczciwym sprawdzianem — na przykład takie, które by się nie skompilowały — pozostają poza wynikiem. Annotated Source ma pod każdym takim wierszem dodatkowy wiersz oraz przycisk Next Mutant (U), a raporty HTML mają sekcję Surviving Mutants z odnośnikami do wiersza. Niczego nie trzeba włączać, a projekt bez raportu mutacyjnego nic z tego nie zobaczy.
Screenshot pending — add assets/img/mutants.gif (see SCREENSHOTS.md).Czy test by zauważył? Przebieg mutacyjny przy kursorze
Przebieg mutacyjny projektu trwa godzinę; jednej funkcji — minutę. Run Mutation Tests Here uruchamia tę minutę: funkcję, w której stoi kursor — albo zaznaczone wiersze, albo plik — runner mutacyjny folderu dostaje do zmutowania, a jego raport jest wczytywany obok pokrycia na ekranie, gdzie oznaczane są mutanty, które przeżyły. Dla C# jest to Stryker.NET (dotnet tool install --global dotnet-stryker), który dostaje zakres znaków i projekt testowy odwołujący się do projektu pliku; dla JavaScriptu i TypeScriptu StrykerJS, który dostaje wiersze; dla Javy PIT z Mavenem, który dostaje klasę. Sposób zakończenia runnera nie obciąża przebiegu: wynik poniżej progu to kod wyjścia, a raport nadal jest. O runnerze, który niczego nie zapisał, pojawia się informacja wraz z tym, co musi być zainstalowane.
Screenshot pending — add assets/img/mutation-here.gif (see SCREENSHOTS.md).
Screenshot pending — add assets/img/vs-mutation-here.gif (see SCREENSHOTS.md).Własny widok Test Coverage VS Code
Przy włączonym testCoverage.publish (domyślnie) każdy wczytany przebieg trafia też do natywnego widoku Test Coverage edytora — panelu pokrycia w Test Explorer, procentów per plik, które stawia w Eksploratorze, i własnego przełącznika edytora Show Inline Coverage — jako wiersze, gałęzie i funkcje, ze szczegółami wczytywanymi na żądanie, z jakiegokolwiek pliku śledzenia pochodzą i bez udziału żadnego adaptera testów. Show in Test Coverage View publikuje aktywny przebieg i otwiera panel, cokolwiek mówi ustawienie; menu paska stanu oferuje to za quickActions.showTestCoverage. Przy wyłączonym w Test Explorer nie pojawia się w ogóle żaden wpis Fucini Coverage. Gdy plik śledzenia nazywa swoje testy (sekcje TN: w lcov), każdy test pojawia się pod Fucini Coverage w Test Explorer, a widok może filtrować pokrycie pliku według testu.
Screenshot pending — add assets/img/test-coverage-view.png (see SCREENSHOTS.md).Niepokryte wiersze w panelu Problems
Domyślnie wyłączone, bo z natury hałaśliwe, i zawsze tylko dla otwartych dokumentów — przebieg z dwoma tysiącami plików nie zaleje panelu. Niezależne od problems.enabled, które trzyma się jednego wpisu na plik:
{
"fuciniCoverage.problems.perLine": "uncoveredAndPartial"
}
Screenshot pending — add assets/img/problems-panel.png (see SCREENSHOTS.md).9. Pokrycie różnicowe
Ogranicz dekoracje do linii, które zmieniły się względem bazowej referencji git — idealne do przeglądu dokładnie tego, co dany PR pokrył, a czego nie:
{
"fuciniCoverage.gitDiff.enabled": true,
"fuciniCoverage.gitDiff.baseRef": "origin/main"
}
Screenshot pending — add assets/img/diff-coverage.png (see SCREENSHOTS.md).W Visual Studio. Te same dwa ustawienia, czytane z tych samych plików: rozszerzenie samo uruchamia git diff <baseRef> dla każdego pliku uruchomienia i ogranicza uruchomienie do wierszy zmienionych przez Twoją gałąź — na marginesie, w oknie Coverage i w progach. Panel Output mówi, co odpowiedział git, gdy nie odpowiada nic.
Bramka dla nowego kodu
threshold.newCode to osobna bramka, obok bramek dla całego przebiegu: najmniejszy procent, który musiał się wykonać, spośród mierzalnych wierszy zmienionych względem gitDiff.baseRef. Projekt mający łącznie 62% może mimo to wymagać, by to, co powstaje dziś, było przetestowane. Jest liczona przy każdym wczytaniu na całym przebiegu, który pozostaje na ekranie — gitDiff.enabled to co innego: zmienione wiersze w miejsce przebiegu. Check Coverage Thresholds i wpisy zgodności w panelu Problems zgłaszają jej niespełnienie osobnym zdaniem: New code 72.00% < 80% (18 of 25 line(s) changed against origin/main ran). Zmiana bez żadnego mierzalnego wiersza — komentarze, README — nie narusza niczego.
{
"fuciniCoverage.threshold.newCode": 80,
"fuciniCoverage.gitDiff.baseRef": "origin/main"
}
Screenshot pending — add assets/img/new-code-gate.png (see SCREENSHOTS.md).
Screenshot pending — add assets/img/vs-new-code-gate.png (see SCREENSHOTS.md).Nowy kod według tagu, autora, daty
Nowy kod to domyślnie wiersze, które drzewo robocze zmienia względem gitDiff.baseRef — gałęzi, commita lub tagu: "v1.4.0" to wszystko od tamtego wydania. Dwa ustawienia pytają o to, czego ref nie potrafi wyrazić. gitDiff.author przyjmuje fragment nazwy autora, a nowym kodem są wtedy wiersze, które git przypisuje temu autorowi; gitDiff.since przyjmuje dzień, a nowym kodem są wiersze ostatnio zmienione tego dnia lub później, niezależnie od gałęzi, którą trafiły; oba naraz — wiersze tego autora od tego dnia. Są odczytywane z git blame, plik po pliku — co duży przebieg odczuje przy każdym wczytaniu — i zastępują diff w pokryciu różnicowym i w bramce powyżej. Wiersz jeszcze niezatwierdzony liczy się w obu przypadkach.
{
"fuciniCoverage.gitDiff.author": "Ada",
"fuciniCoverage.gitDiff.since": "2026-09-01"
}
Screenshot pending — add assets/img/new-code-author.png (see SCREENSHOTS.md).Zmiany pośrednie: co się zmieniło, choć nikt tego nie dotykał
Diff mówi, które wiersze się zmieniły; dwa przebiegi mówią, które wiersze przestały lub zaczęły się wykonywać. Warto spojrzeć na te wiersze, co do których jedno z drugim się nie zgadza: kod, którego nikt nie edytował, a który już się nie wykonuje, bo usunięto test, bo gałąź wyżej w kodzie kończy teraz funkcję wcześniej, bo zmieniła się fixtura. Przegląd diffu ich nie zobaczy — z definicji są poza nim. Show Indirect Coverage Changes… wypisuje je per plik, najpierw plik, który stracił najwięcej, i otwiera wybrany na pierwszym takim wierszu. Przebieg jest porównywany z linią bazową CI tam, gdzie baseline.report ją wskazuje — według niej oceniany jest pull request — a w przeciwnym razie z poprzednim przebiegiem; pomijane są wiersze, które drzewo robocze zmienia względem gitDiff.baseRef, i wszystko poniżej miejsca, w którym ta zmiana przesuwa wiersze pliku.
Screenshot pending — add assets/img/indirect-changes.png (see SCREENSHOTS.md).
Screenshot pending — add assets/img/vs-indirect-changes.png (see SCREENSHOTS.md).10. Wynik złożony
Zamiast raportować sześć liczb, rozszerzenie łączy je w jedną ważoną średnią harmoniczną (WHM). Dla metryk z procentami pᵢ i wagami wᵢ:
WHM = ( Σ wᵢ ) / ( Σ wᵢ / pᵢ )
Średnia harmoniczna jest zdominowana przez swój najmniejszy składnik, więc słaba metryka nie może zostać zamaskowana przez idealną — dokładnie tę właściwość chcesz uzyskać od bramki bezpieczeństwa. Domyślne wagi:
| Metryka | Waga | Uzasadnienie |
|---|---|---|
| MC/DC | 4 | IEC 61508 SIL 3–4 / ISO 26262 ASIL C–D / DO-178C DAL A–B. |
| Gałęzie | 2 | IEC 61508 SIL 2+ / ISO 26262 ASIL B+. |
| Warunki | 3 | Między gałęziami a MC/DC (DO-178C, ISO 26262). |
| Regiony | 1.5 | Ścieżki wewnątrz instrukcji (np. częściowe zwarcie logiczne). |
| Wiersze | 1 | IEC 61508 SIL 1+ / ISO 26262 ASIL A+. |
| Funkcje | 1 | Bramka martwego kodu. |
| Instancjacje | 0.5 | Pokrycie szablonów C++; najwęższy zakres. |
| Wywołania funkcji | 1 | Miejsca wywołań, które zostały wykonane (gcov, VectorCAST, Testwell CTC++, TRACE32). |
| Kod obiektowy | 0 | Wyłączone, dopóki nie nadadzą mu Państwo wagi: obejmuje pokrycie instrukcji. |
| Wynik mutacyjny | 0 | Wyłączone, dopóki nie nadadzą mu Państwo wagi: to nie jest pokrycie. |
Ustaw dowolną wagę na 0, aby usunąć tę metrykę z wyniku. Metryki nieobecne w danych (np. MC/DC w zwykłym przebiegu lcov) są po prostu pomijane.
Kod obiektowy i wynik mutacyjny mają wagę 0, dopóki nie zdecydują Państwo inaczej (whmWeights.objectCode, whmWeights.mutation). Pokrycie kodu obiektowego obejmuje pokrycie instrukcji, więc ważenie obu liczy ten sam dowód dwukrotnie; wynik mutacyjny w ogóle nie jest pokryciem — zestaw testów może wykonać każdy wiersz i niczego nie wykryć. Obie metryki mają jednak własną kolumnę i własny próg.
Pokrycie warunków
a && b to jedna decyzja — dwie gałęzie — i dwa warunki o czterech wynikach. Zestaw testów może przejść obie gałęzie i nigdy nie zobaczyć b o wartości fałsz: pokrycie gałęzi jest pełne, a pokrycie warunków wynosi trzy z czterech. Ten poziom mieści się w DO-178C i ISO 26262 między pokryciem gałęzi a MC/DC, a od wersji 0.2026.83 jest osobną metryką, zamiast być wliczanym do gałęzi: wiersz w kartach paska stanu, kolumna w widoku Coverage, w raportach i eksportach, waga 3 w wyniku (whmWeights.conditions) oraz bramka (threshold.conditions; bez bramki w profilu standard, 100 w profilu safety).
Odczytywane z sond condition narzędzia BullseyeCoverage, z eksportu cond TRACE32 oraz z GCC 14 przy kompilacji z opcją -fcondition-coverage. Raport, który nie odróżnia warunków od decyzji, nie ma takiego wiersza, kolumny ani wagi. Jeśli używają Państwo Bullseye lub TRACE32: warunki były dotąd liczone jako gałęzie, więc wraz z tym wydaniem zmienia się procent gałęzi, a z nową wagą także wynik złożony; aby uzyskać wynik taki jak dotychczas, należy ustawić whmWeights.conditions na 0.
GCC 14, wiersz po wierszu. -fcondition-coverage sprawia, że gcov mówi, którego wyniku którego warunku brakuje — warunek 1 nigdy prawdziwy, warunek 0 nigdy ani tak, ani tak — a każdy warunek jest oznaczany w swoim wierszu i wymieniany w podpowiedzi po najechaniu, na podstawie JSON-a gcov i jego listingu tekstowego (condition outcomes covered 3/6). Metryka jest tam, gdzie pozostałe: threshold.conditions stawia dla niej bramkę i pozostaje bez oceny tam, gdzie przebieg nie ma takiej liczby, Copy Coverage Summary ma kolumnę warunków, badge.metric przyjmuje conditions, a pole wyszukiwania przyjmuje conditions < 80. Wartość gałęzi dla funkcji pomija wyniki jej warunków, tak jak wartość dla pliku i dla przebiegu.
Screenshot pending — add assets/img/gcc-conditions.png (see SCREENSHOTS.md).Złożoność i CRAP
Niektóre raporty zawierają złożoność cyklomatyczną każdej funkcji: OpenCover (czyli to, co zapisuje Coverlet), JaCoCo, Clover i Cobertura. W takim przypadku rozszerzenie oblicza dla funkcji wynik CRAP — Change Risk Anti-Patterns — na podstawie tej złożoności oraz pokrycia, które samo zmierzyło:
CRAP = complexity² × (1 − coverage)³ + complexity
Prosta, w pełni przetestowana funkcja uzyskuje wynik równy własnej złożoności i nic ponadto; złożona i ledwie przetestowana uzyskuje wynik liczony w setkach. W przykładzie C# w projekcie demonstracyjnym Price() ma złożoność 22 i około 37% pokrytych wierszy, co daje 142.2, natomiast Shipping() ma złożoność 12 i jest w pełni pokryta, co daje 12. Zwyczajowa granica to 30: funkcja, która ją osiąga lub przekracza, jest wymieniana w sekcji Riskiest Methods raportu HTML, od najgorszej.
Złożoność i wynik są widoczne w CodeLens funkcji oraz obok funkcji w źródle z adnotacjami. Max CRAP to najwyższy wynik spośród wszystkich funkcji w pliku — najgorszy, a nie średnia — i stanowi kolumnę w widoku Coverage, w raporcie HTML oraz w eksportach CSV i Markdown. Jest to informacja: nie ma progu ani wagi w wyniku złożonym. Raporty, które nie zawierają złożoności (lcov, gcov, Istanbul, coverage.py), nie mają CRAP ani pustej kolumny.
Od wersji 0.2026.83 mają go także C i C++. llvm-cov nie podaje złożoności, więc jest ona liczona z danych o gałęziach, które raport już zawiera: warunki zapisane we własnym pliku funkcji, plus jeden — to definicja McCabe’a i to samo, co narzędzia działające na poziomie kodu źródłowego liczą dla .NET i Javy. Warunki pochodzące z makra z innego pliku, na przykład każdy assert, nie są liczone.
Screenshot pending — add assets/img/riskiest-methods.png (see SCREENSHOTS.md).Risk hotspots i które pliki pokazywać
Pod drzewem widoku Coverage Risk hotspots wymienia funkcje, w których złożony kod spotyka się z małym pokryciem, najgorsze najpierw, a każda otwiera swój plik na tej funkcji. Funkcja kwalifikuje się przez wynik CRAP — hotspots.crapThreshold, domyślnie 30, liczba zaproponowana przez autorów metryki — albo przez samą złożoność cyklomatyczną, hotspots.complexityThreshold, domyślnie wyłączone; mają je tylko raporty niosące złożoność (OpenCover, Cobertura z Coverleta, JaCoCo, llvm-cov). Community widzi liczbę i najgorszy wynik; lista rankingowa jest w Pro. Obok sortowania drugie menu rozwijane mówi, które pliki pokazuje drzewo — wszystkie, pliki z lukami, pliki nieprzetestowane albo pliki zmienione od ostatniego uruchomienia; foldery podążają za swoimi plikami i zachowują własne liczby. Oba są też w Visual Studio, w oknie Coverage.
Screenshot pending — add assets/img/vs-hotspots.png (see SCREENSHOTS.md).Przestrzenie nazw, klasy i metody
Dla raportu .NET, który nazywa swoje klasy — Cobertura i coverage.cobertura.xml Coverleta, OpenCover — trzecie menu rozwijane, Folders / Namespaces, rysuje ten sam przebieg jako przestrzenie nazw, klasy i metody: liczba przestrzeni nazw to suma jej klas, klasy — jej metod, dokładnie tak, jak liczba folderu to suma jego plików, z tym samym sortowaniem i tym samym filtrem. Wiersz metody otwiera plik na tej metodzie; klasa zadeklarowana poza przestrzenią nazw jest pod (no namespace). Wybór zapisywany jest w coverageView.perspective; przebieg, który nie niesie nazw klas, nie ma menu rozwijanego i pokazuje swoje foldery. W Visual Studio okno Coverage ma to samo menu rozwijane.
Screenshot pending — add assets/img/namespace-perspective.png (see SCREENSHOTS.md).
Przeszukiwanie drzewa
Pod przyciskami i menu rozwijanymi pole wyszukiwania. Słowo zachowuje wiersze, których nazwa lub ścieżka je zawiera — każde wpisane słowo musi tam być; porównanie zachowuje wiersze, których liczba je spełnia — < 80% na wyniku, lines >= 90, branches = 0, functions != 100, mcdc < 50 — a invoice < 80 wymaga obu. Wiersze metod z perspektywy przestrzeni nazw i punkty ryzyka są przeszukiwane razem z plikami, więc funkcja jest znajdowana tam, gdzie ma ją przebieg. Drzewo jest filtrowane w trakcie pisania, w stronie, bez ponownego rysowania; folder zawierający dopasowanie otwiera się dla niego i zamyka z powrotem, gdy pole się opróżni; Esc je czyści. To samo pole, ta sama gramatyka, w Visual Studio.
Screenshot pending — add assets/img/tree-search.gif (see SCREENSHOTS.md).lines < 80.Drzewo podąża za edytorem
Plik, na który patrzysz, jest podświetlany w widoku Coverage, foldery nad nim są rozwijane, a jego wiersz jest przewijany tak, by był widoczny — nie trzeba już szukać w drzewie pliku, który i tak jest otwarty. Poza tym drzewo zachowuje pozycję przewijania i nic nie jest rysowane od nowa. coverageView.followActiveEditor, domyślnie włączone, wyłącza to dla tych, którzy wolą zostawić drzewo tam, gdzie je ustawili.
Screenshot pending — add assets/img/follow-editor.gif (see SCREENSHOTS.md).
Screenshot pending — add assets/img/vs-follow-editor.gif (see SCREENSHOTS.md).11. Bramkowanie zgodności
Werdykt COMPLIANT / NON-COMPLIANT (pokazywany w widoku z adnotacjami źródła, raporcie HTML i obu podpowiedziach paska stanu) jest determinowany przez progi dla poszczególnych metryk oraz tryb:
Screenshot pending — add assets/img/statusbar.png (see SCREENSHOTS.md).| Tryb | COMPLIANT, gdy… |
|---|---|
strict (default) | każda osobno kontrolowana metryka osiąga własny próg — bez kompromisów. |
whm | pojedynczy ważony wynik złożony osiąga threshold.weighted. |
both | spełnione są bramka ważona ORAZ ścisła bramka dla każdej metryki. |
either | spełniona jest bramka ważona LUB ścisła bramka dla każdej metryki (najluźniej). |
Próg 0 wyłącza daną bramkę, a metryka, której raport nie zawiera, nigdy nie jest oceniana. O tym, co oznacza próg, którego Państwo nie ustawili, decyduje profil opisany poniżej. Aby przeprowadzić ocenę na żądanie, proszę uruchomić Fucini Coverage: Check Coverage Thresholds.
W Visual Studio. Tools → Coverage Studio → Check Coverage Thresholds ocenia uruchomienie według tych samych kluczy threshold.* i mówi to na pasku stanu i w panelu Output; z compliance.diagnostics, problems.enabled, problems.perLine lub deadCode.enabled ustalenia trafiają do Error List obok tych od kompilatora — jeden wpis na plik poniżej progu, jeden na niepokryty zakres, jeden na funkcję, która nigdy nie została wykonana — a każdy otwiera swój plik na tym wierszu.
Screenshot pending — add assets/img/vs-error-list.png (see SCREENSHOTS.md).Profile progów
threshold.profile rozstrzyga, co oznacza próg, którego Państwo nie ustawili. standard, wartość domyślna od wersji 0.2026.82, to poziom, jakiego można wymagać od zwykłego projektu niezwiązanego z bezpieczeństwem funkcjonalnym. safety to każda bramka na poziomie 100 — tego wymaga dowód bezpieczeństwa (safety case) i dokładnie tak było dostarczane do wersji 0.2026.81.
| Metryka | standard | safety |
|---|---|---|
| Wiersze | 80 | 100 |
| Funkcje | 80 | 100 |
| Regiony | 75 | 100 |
| Gałęzie | 70 | 100 |
| Wynik złożony | 75 | 100 |
| MC/DC, instancjacje, wywołania funkcji, kod obiektowy | bez bramki | 100 |
| Warunki | bez bramki | 100 |
| Wynik mutacyjny | bez bramki | bez bramki |
Próg, który Państwo ustawili, ma pierwszeństwo przed każdym z profili. Przykład ustawia bramkę gałęzi na 90, a wszystko inne na 100; aby wymagać 100 tylko od niektórych metryk, proszę pozostać przy standard i ustawić je samodzielnie. Jedno zastrzeżenie wynika ze sposobu działania ustawień: wartości równej dostarczanej wartości domyślnej nie da się odróżnić od braku wartości, dlatego w profilu safety próg zapisany dokładnie jako jego wartość standardowa — na przykład 80 dla wierszy — nadal liczy się jako 100.
{
"fuciniCoverage.threshold.profile": "safety",
"fuciniCoverage.threshold.branch": 90
}
Screenshot pending — add assets/img/threshold-profile.png (see SCREENSHOTS.md).
Screenshot pending — add assets/img/threshold-profiles.gif (see SCREENSHOTS.md).Jeśli polegali Państwo na dawnych wartościach domyślnych, po aktualizacji do wersji 0.2026.82 ocena będzie łagodniejsza, dopóki nie wybiorą Państwo safety. Instalacja, która działała już wcześniej, jest o tym informowana jeden raz, wraz z przyciskiem Keep 100% (safety), który zapisuje profil w ustawieniach użytkownika; w przypadku wspólnego projektu proszę umieścić go również w ustawieniach obszaru roboczego, aby wszyscy byli oceniani jednakowo. Configure Coverage Compliance & Thresholds... pokazuje profil nad siatką progów, a podgląd na żywo ocenia według bramek faktycznie obowiązujących. W każdej karcie i każdym raporcie metryka, której bramka jest wyłączona, pokazuje swoją wartość z neutralną kreską zamiast znacznika wyboru lub krzyżyka.
Screenshot pending — add assets/img/statusbar-metrics.png (see SCREENSHOTS.md).11a. Pokrycie kodu obiektowego
Każda inna miara tutaj mierzona jest ze źródeł: narzędzie instrumentuje kod, instrumentowana kompilacja się wykonuje, a liczniki mówią, które instrukcje, gałęzie czy warunki zostały wykonane. Pokrycie kodu obiektowego mierzy co innego — jaka część zbudowanego pliku binarnego faktycznie się wykonała, liczona w bajtach instrukcji, przez obserwację strumienia instrukcji, a nie przez instrumentację źródeł. Ma to znaczenie, bo kompilator emituje kod, za którym nie stoi żaden wiersz źródła: kontrole zakresu tablic, tablice skoków switch, zrzuty rejestrów, sondy stosu, wywołania procedur pomocniczych środowiska wykonawczego dla dzielenia lub liczb zmiennoprzecinkowych na rdzeniach bez odpowiedniej instrukcji. To także jedyna tutaj miara odpowiadająca na pytanie czy to obejmuje asembler? — ręcznie pisany asembler nigdy nie jest instrumentowany, a narzędzie działające na źródłach do niego nie sięga. DO-178C mówi wprost dlaczego: na poziomie A, gdy kompilator lub konsolidator generuje kod, którego nie da się bezpośrednio prześledzić do instrukcji źródłowych, cel 6.4.4.2b wymaga dodatkowej weryfikacji dokładnie tego wygenerowanego kodu.
Obejmuje pokrycie instrukcji — każda wykonana instrukcja maszynowa pochodzi z jakiejś instrukcji źródłowej, więc 100% pokrycia kodu obiektowego oznacza 100% pokrycia instrukcji. Odwrotnie to nie działa i właśnie ta asymetria jest sensem pomiaru. Wynikają z tego dwie rzeczy. Nie ma żadnej wagi w wyniku złożonym, bo uśrednianie dwóch miar tych samych wykonań liczy ten sam dowód dwukrotnie; zamiast tego jest bramkowane przez fuciniCoverage.threshold.objectCode — wymaganie, a nie waga, dokładnie tak, jak żąda tego norma. I to luka jest produktem: przebieg ze 100% pokryciem wierszy i mniejszym niż 100% pokryciem kodu obiektowego wskazał dokładnie ten wygenerowany przez kompilator kod, za którym nie stoi Twoje źródło, więc karta zgodności mówi 312 bajtów nigdy nie wykonano, przy 100% pokryciu wierszy, zamiast ukrywać to jako «94%». Odwrotność — cały plik binarny zgłoszony jako wykonany, choć jego źródło nie — to sprzeczność, a nie niski wynik: niemal zawsze nieaktualny plik śledzenia po jednej stronie scalenia albo nazwy modułów, które nigdy nie pasowały do ścieżek plików. Zgłaszane jest to jako ustalenie.
Pokrycie kodu obiektowego wymaga, by plik binarny działał tam, gdzie da się obserwować jego instrukcje. Są trzy drogi i różnią się kosztem ogromnie. Tylko trzecia daje pokrycie kodu obiektowego; dwie pierwsze są tu dlatego, że rozwiązują pokrewny problem — często ten, który naprawdę warto rozwiązać.
- Instrumentowana kompilacja działająca na urządzeniu docelowym. Kompilatory skrośne GCC przyjmują
-fprofile-arcs -ftest-coverage, więc instrumentacja działająca na stacji roboczej działa i na celu — tyle że system bez systemu operacyjnego nie ma systemu plików, do którego zapisałby liczniki.gcda, a często nie ma teżexit(), przy którym miałby to zrobić. Liczniki i tak są w pamięci RAM, więc rozwiązaniem jest zrzucenie tej pamięci i odtworzenie plików poza celem;embedded-gcovz NASA JPL (Apache-2.0) robi dokładnie to, bez systemu plików, systemu operacyjnego i standardowej biblioteki C. Daje to pokrycie instrukcji, gałęzi i funkcji kompilacji wykonanej Twoim kompilatorem skrośnym, dla Twojej listy rozkazów, na Twoim sprzęcie — ale nie pokrycie kodu obiektowego, a mierzony plik binarny jest instrumentowany, więc większy i wolniejszy od tego, który wysyłasz. Wynik wczytaj jako LCOV, gcovr JSON, gcov JSON albo — na łańcuchu narzędzi starszym niż GCC 9 — jako tekstowy listing.gcov. - Symulator listy rozkazów. Uruchom prawdziwy docelowy plik binarny w symulatorze i wyprowadź pokrycie z wykonanych adresów: bez sprzętu, bez instrumentacji, bez sondy, a ponieważ obserwuje rozkazy, może dać prawdziwe pokrycie kodu obiektowego. Ograniczeniem jest wierność: symulator dobrze modeluje rdzeń, a gorzej peryferia, więc wyniki dla całego systemu traktuj podejrzliwie, o ile nie modeluje on dokładnie Twojego układu.
- Śledzenie na układzie i debugger. Droga klasy certyfikacyjnej i jedyna naprawdę nieinwazyjna: jednostka śledząca rdzenia przekazuje strumień rozkazów do debuggera, który zamienia go w pokrycie. Nic nie jest instrumentowane, rozmiar kodu się nie zmienia, a czasy pozostają nienaruszone — i właśnie to czyni wynik dowodem o pliku binarnym, który faktycznie wysyłasz. Sprawdź układ, zanim to zabudżetujesz: w wielu rodzinach mikrokontrolerów pełne śledzenie dostępne jest tylko w wariancie emulacyjnym lub deweloperskim z dużym buforem i szybkim portem śledzenia, podczas gdy układy produkcyjne mają okrojoną jednostkę śledzącą, dla której producent proponuje śledzenie programowe — instrumentujące kod i zjadające czas procesora, czyli usuwające dokładnie tę właściwość, dla której tę drogę wybrano.
Wiele projektów wbudowanych mierzy pokrycie, kompilując te same źródła na maszynę deweloperską i uruchamiając tam testy jednostkowe. To szybkie, nie wymaga sprzętu i dla większości zespołów jest właściwym domyślnym wyborem — warto jednak jasno powiedzieć, co ten dowód właściwie opisuje: inny kompilator, inny optymalizator, inną listę rozkazów i inny plik binarny niż ten, który jest wysyłany. Dla większości oprogramowania to akceptowalny i dobrze rozumiany kompromis. Dla prac ocenianych względem IEC 61508, ISO 26262 lub DO-178C jest to standardowy zarzut „host kontra cel”, a powyższe drogi są standardowymi odpowiedziami na niego — pierwsza zamyka go dla pokrycia źródeł, trzecia dla kodu obiektowego.
Obecnie eksport odczytywany dla kodu obiektowego to COVerage.EXPORT.ListModule z Lauterbach TRACE32 z metric="object"; wczytaj go jak każdy inny plik śledzenia. Ta miara jest liczona i bramkowana wyłącznie na licencji płatnej i w okresie oceny. Instalacja Community jej nie liczy — ale jest informowana, gdy plik śledzenia ją zawiera, bo werdykt zgodności, który po cichu pominąłby najmocniejszy dowód w pliku, byłby gorszy niż taki, który mówi, co pominął.
12. Wykluczanie linii niebędących kodem
Przy włączonym excludeComments (domyślnie), instrukcje, które w całości znajdują się na liniach tylko z komentarzem lub pustych, są wykluczane z sum — neutralizuje to też znaną osobliwość llvm-cov/gcov, gdzie przypadkowy licznik trafień ląduje na komentarzu. Honorowane są też standardowe znaczniki:
x = risky(); // LCOV_EXCL_LINE
// LCOV_EXCL_START
debug_only_block();
// LCOV_EXCL_STOP
Dyrektywy preprocesora również nie liczą się jako kod w C, C++, Objective-C, CUDA i C#: wiersz zaczynający się od # — #define, #include, #if — oraz wiersze, na które przedłuża go końcowy ukośnik wsteczny. gcov przypisuje każde użycie makra wierszowi, w którym jest ono zdefiniowane, więc nagłówek, którego jedynym raportowanym wierszem było #define CHANNEL_COUNT (33U), wyglądał na pokryty w 100%, bo pętla w pliku .c dochodziła do niego, a ten, którego stałej nic nie używało — na pokryty w 0%. Taki nagłówek nie ma teraz nic do zmierzenia i nie pojawia się na liście.
Ustaw excluded.includeInTotals na true, aby mimo to liczyć wykluczone linie.
Pomijanie pliku lub folderu, z drzewa
Kliknij prawym przyciskiem plik lub folder w widoku Coverage i wybierz Exclude from Coverage — jest też wśród akcji ścieżki wiersza — albo uruchom Exclude This File from Coverage na otwartym pliku: ścieżka pliku względem obszaru roboczego, albo /** folderu, trafia do fuciniCoverage.ignore w ustawieniach folderu, jednorazowo, a ponowne wczytanie usuwa go z każdej sumy i każdej strony; wzorzec jest tam po to, by można go było znów usunąć. W Visual Studio menu wiersza i Tools → Coverage Studio mają te same dwa polecenia, zapisujące to samo ustawienie do tego samego pliku.
Screenshot pending — add assets/img/exclude-from-tree.gif (see SCREENSHOTS.md).
fees.ts — drzewo bez niego, wzorzec w .vscode/settings.json.Atrybuty i przestrzenie nazw, dla .NET
Dwa ustawienia odczytują ze źródła to, czego raport powiedzieć nie potrafi. ignore.attributes — domyślnie ExcludeFromCodeCoverage — wyklucza klasę, metodę lub właściwość pod atrybutem, który wymienia, tak jak zrobiłby to LCOV_EXCL_START/STOP, niezależnie od tego, które narzędzie zapisało raport: Coverlet honoruje ten atrybut, OpenCover, dotCover i przekonwertowany lcov nie, a teraz wszystkie się zgadzają. Nazwy z przyrostkiem Attribute lub bez, z przestrzenią nazw lub bez; dodaj GeneratedCode, Obsolete albo własne. ignore.namespaces pomija każdy plik, którego deklaracja przestrzeni nazw pasuje do prefiksu, z * jako symbolem wieloznacznym — Acme.Generated, Acme.*.Migrations, *Tests — a panel Output wymienia pliki, które zabrał. Oba są odczytywane w tym samym przebiegu, który czyta znaczniki w komentarzach, w obu edycjach.
{
"fuciniCoverage.ignore.attributes": ["ExcludeFromCodeCoverage", "GeneratedCode"],
"fuciniCoverage.ignore.namespaces": ["Acme.Generated", "*.Migrations"]
}
Wykluczanie z edytora
Zaznacz wiersze i wybierz Exclude Selection from Coverage z żarówki, menu kontekstowego edytora lub Command Palette — w Visual Studio z żarówki (Ctrl+.), menu prawego przycisku w oknie kodu, Tools → Coverage Studio lub Ctrl+Shift+U, X — a wykluczenie zostanie zapisane tam, gdzie jest kod: [ExcludeFromCodeCoverage] nad klasą, metodą lub właściwością C#, VB lub F#, krótką nazwą, gdy plik już importuje System.Diagnostics.CodeAnalysis, a w pełni kwalifikowane, gdy nie, aby nie trzeba było dodawać żadnego using; LCOV_EXCL_LINE na końcu jednego wiersza kodu; LCOV_EXCL_START i LCOV_EXCL_STOP wokół kilku, z wcięciem pierwszego wiersza — własnym znakiem komentarza danego języka, //, #, ', -- lub ;. Jeden krok cofania. Żarówka oferuje to także na wierszu, który wpisy w Problems oznaczają jako niepokryty. Wiersz już oznaczony albo składowa już opatrzona atrybutem pozostają bez zmian.
Screenshot pending — add assets/img/exclude-selection.gif (see SCREENSHOTS.md).
LCOV_EXCL wokół gałęzi, potem [ExcludeFromCodeCoverage] nad metodą.Tylko gałęzie, i znaczniki gcovr
Defensywny else, default:, do którego nie trafia żadna wartość, odnoga dodana przez kompilator na wypadek wyjątku: wiersz się wykonuje i powinien się liczyć, a tylko jego gałęzi nie da się wziąć. LCOV_EXCL_BR_LINE oraz LCOV_EXCL_BR_START … LCOV_EXCL_BR_STOP wyłączają z liczenia gałęzie w swoich wierszach, a same wiersze w nim zostawiają. LCOV_EXCL_EXCEPTION_BR_LINE i jego region wyłączają jeszcze mniej — tylko odnogi, do których prowadzi wyjątek, o ile raport mówi, które to są, jak robi to JSON gcov. Każdy znacznik jest czytany także z prefiksami gcovr: GCOVR_EXCL_LINE, GCOVR_EXCL_START, GCOVR_EXCL_BR_LINE, GCOV_EXCL_STOP i pozostałe znaczą to samo co znaczniki LCOV_EXCL_, więc źródło napisane pod gcovr czyta się tu tak samo, niezależnie od narzędzia, które utworzyło raport. Nie jest czytany: GCOVR_EXCL_FUNCTION — nic w tym wierszu nie mówi, gdzie funkcja się kończy.
if (handle == NULL) return E_FAIL; // LCOV_EXCL_BR_LINE: the allocator never fails on target
// LCOV_EXCL_BR_START generated state table
switch (state) { /* … */ }
// LCOV_EXCL_BR_STOP
Screenshot pending — add assets/img/branch-markers.png (see SCREENSHOTS.md).Powiedzieć dlaczego: uzasadnione wykluczenia
Wyłączenie kodu z liczenia to twierdzenie — „tego nie da się przetestować”, „to pomoc dla programisty” — a w DO-178C, ISO 26262 czy IEC 61508 twierdzenie, które zmienia liczbę, na której opiera się certyfikat, musi być zapisane i możliwe do przejrzenia. Dlatego wykluczenie może podać powód tam, gdzie jest zapisane: tekst po LCOV_EXCL_LINE lub LCOV_EXCL_START albo Justification atrybutu [ExcludeFromCodeCoverage].
abort(); // LCOV_EXCL_LINE: defensive, unreachable by construction
// LCOV_EXCL_START debug dump, never built for the target
[ExcludeFromCodeCoverage(Justification = "a developer aid")]
public static void DebugDump(decimal amount) { /* … */ }
Powody są czytane przy każdym wczytaniu, a log je zlicza. Export Coverage Report… zapisuje listę — wykluczenia i ich uzasadnienia, jako Markdown lub CSV: plik, wiersze, sposób zapisu oraz uzasadnienie albo none given. Plik, w którym nie zostało nic mierzalnego, nadal jest na tej liście. Przy włączonym exclusions.requireReason wykluczenie bez powodu jest ustaleniem: ostrzeżeniem w panelu Problems w swoim wierszu i niespełnieniem Check Coverage Thresholds. Exclude Selection from Coverage pyta wtedy najpierw o powód i zapisuje go razem ze znacznikiem albo jako Justification atrybutu; gdy pytanie zostanie odrzucone lub pozostawione puste, nic nie jest wykluczane.
Screenshot pending — add assets/img/justified-exclusions.png (see SCREENSHOTS.md).
Screenshot pending — add assets/img/vs-justified-exclusions.png (see SCREENSHOTS.md).12a. Czy to pokrycie nadal opisuje ten plik?
Pokrycie odczytane z pliku śladu opisuje kod w postaci, w jakiej był podczas uruchamiania testów, a większość formatów nie mówi, o którą wersję chodziło. Dlatego każdy plik w panelu Pokrycie jest w jednym z trzech stanów:
- ✓ Zweryfikowany — plik śladu zapisuje treść każdej zmierzonej linii i nadal zgadza się ona z plikiem.
- Bez oznaczenia — nieobalone. Nic nie przeczy pokryciu i nic go nie potwierdza. To stan zwyczajny.
- ⚠ Obalone — sam plik obala swoje pokrycie. Wiersz jest przygaszony, a podpowiedź mówi, co znaleziono.
Tylko dwa formaty mogą zasłużyć na znacznik, bo tylko dwa zapisują cokolwiek o mierzonym kodzie: lcov zapisany z --checksum (domyślnie wyłączone w geninfo; udokumentowanym celem jest właśnie niedopuszczenie do łączenia pokrycia z dwóch wersji pliku) oraz GNATcoverage XML, który osadza tekst każdej zmierzonej linii. Włączenie opcji lcov się opłaca.
Ostrzeżenie nie potrzebuje żadnego z nich i działa z każdym formatem: pokrycie zapisane poza końcem pliku, nazwana funkcja, której nie ma już tam, gdzie umieszcza ją raport, lub wykonane wiersze, które w pliku są puste. Sygnatury czasowe same nigdy nie wystarczą — git checkout zmienia każdą, nie zmieniając ani bajta — więc zmieniona sygnatura czasowa jest co najwyżej powodem, by spojrzeć ponownie. Sprawdzenie odbywa się przy wczytaniu pokrycia i ponownie za każdym razem, gdy plik zostanie zapisany lub zmieni się na dysku, więc oznaczenie podąża za plikiem: edycja przecząca przebiegowi je ustawia, checkout przywracający zmierzoną wersję je usuwa. Podpowiedź mówi dokładnie, co to udowodniło. Ustaw staleWarning.enabled na false, aby wyłączyć to wszystko.
12b. Niezmierzone a niepokryte
Plik, o którym przebieg nigdy nie wspomina, jest niezmierzony: żaden test go nie wczytał, więc żadne narzędzie nie zapisało dla niego ani wiersza. To nie to samo co niepokryty — zmierzony, z zerem trafień — i rozszerzenie nigdy nie oceniało nieobecnego pliku jako 0%. Czego nie robiło aż do 0.2026.69, to pokazywanie nieobecnych w ogóle: moduł bez jakichkolwiek testów nigdy nie pojawiał się w drzewie, w sumach ani w sprawdzeniu progów, a czytelnik widział „92%” dla projektu, w którym połowa plików nigdy nie została przećwiczona.
Teraz, przy wczytanym przebiegu, element paska stanu dla pliku mówi not measured o pliku źródłowym rodzaju przebiegu, którego przebieg nie zawiera — „rodzaju przebiegu” znaczy, że ma jedno z rozszerzeń plików, które przebieg mierzył, więc nagłówki i źródła projektu w C są kandydatami, a jego skrypty w Pythonie nie. Wszystko poza tym jest opcjonalne przez fuciniCoverage.unmeasured.mode:
off(domyślnie) — nic więcej się nie zmienia.list— widok Coverage dostaje na dole grupę Unmeasured wymieniającą każdy taki plik, a każdy wiersz go otwiera; wynik wczytania je zlicza; odznaki oznaczają je?w Eksploratorze; afuciniCoverage.threshold.unmeasuredFilesmoże oblać Check Coverage Thresholds, gdy jest ich więcej niż ustawiona przez Ciebie liczba. Żaden procent się nie rusza.count— wszystko, co robilist, a ponadto każdy niezmierzony plik liczy się na niekorzyść przebiegu jako niepokryty plik o tylu wierszach, ile ma wierszy kodu, więc pasek stanu, progi, odznaki, historia, każdy eksport i widok Test Coverage pokazują niższą liczbę. Plik jest rysowany jako niezmierzony wszędzie, gdzie się pojawia, jego paski na marginesie mówią „not measured”, a nie „nigdy się nie wykonał”, a sprawdzenie niezgodności zostawia go w spokoju — nie ma pomiaru, któremu jego zawartość mogłaby przeczyć.
{
"fuciniCoverage.unmeasured.mode": "list",
"fuciniCoverage.threshold.unmeasuredFiles": 0
}
Pliki nagłówkowe to znany fałszywy alarm w C: mają rodzinę rozszerzeń przebiegu, a żaden plik śledzenia nigdy żadnego nie wymieni, bo sam z siebie kompiluje się do niczego. fuciniCoverage.unmeasured.exclude pomija więc domyślnie **/*.h, **/*.hpp, **/*.hh, **/*.inl i **/*.d.ts, w tej samej składni glob co fuciniCoverage.ignore; dodaj port na platformę, której tu się nie buduje, albo generowane zaślepki, a wypadną z listy, z liczby i ze stanu na pasku stanu. Plik wymieniony w ignore też nigdy nie jest nazywany niezmierzonym — pominięcie go było celem. threshold.unmeasuredFiles domyślnie wynosi -1, co nie sprawdza; 0 oblewa w chwili, gdy jakikolwiek plik rodzaju przebiegu nigdy nie został wczytany przez test, i obowiązuje tylko wtedy, gdy unmeasured.mode to list lub count.
13. Raporty HTML
- Generate Full HTML Report — samodzielnie generowany, wielostronicowy raport per katalog. Wynik trafia do
htmlReport.outputDirlub globalnego magazynu rozszerzenia, gdy nieustawione. - Open Annotated Source — widok z adnotacjami dla jednego pliku. Wskaż
externalHtmlReport.dirna wcześniej zbudowany katalogllvm-cov show --format=html, aby użyć tych stron zamiast wbudowanego renderera. - Export Fucini JSON — pełny znormalizowany model do własnych narzędzi.
- Export Coverage Report... — przebieg jako CSV (na plik lub na funkcję), podsumowanie Markdown, plik śledzenia LCOV, XML Cobertura, SARIF albo samodzielna odznaka SVG do pliku README. Dostępne też z przycisku obok Generate Full HTML Report w widoku Covered Files. Wszystko poza CSV jest stratne — MC/DC, regiony i instancjacje nie mieszczą się w LCOV, Coberturze ani SARIF — więc Fucini JSON i CSV pozostają formatami niosącymi każdą metrykę.
- Copy Uncovered Lines — podsumowanie Markdown każdej luki, gotowe do wklejenia w PR.
W Visual Studio. Grupa Reports w Tools → Coverage Studio: Show Annotated Source otwiera aktywny dokument jako stronę w obszarze dokumentów — każdy wiersz w swoim kolorze, ustalenia obok — przewijaną razem z edytorem w obie strony; Open HTML Report zapisuje jednostronicowy raport do htmlReport.outputDir (albo %LOCALAPPDATA%\Fucini\CoverageStudio\html-report) i otwiera przeglądarkę; Generate Full HTML Report zapisuje tam indeks na folder i stronę na plik; Export Coverage Report… oferuje te same osiem formatów i pyta, gdzie zapisać; Generate Coverage Badge zapisuje odznakę tam, gdzie mówi badge.outputPath, po każdym wczytaniu z badge.autoUpdate. Strona z adnotacjami potrzebuje WebView2, tak jak okno Coverage; raporty na dysku nie.
Screenshot pending — add assets/img/vs-annotated-source.png (see SCREENSHOTS.md).
Screenshot pending — add assets/img/report.png (see SCREENSHOTS.md).
Screenshot pending — add assets/img/report-directory-summary.png (see SCREENSHOTS.md).
Screenshot pending — add assets/img/report-file-summary.png (see SCREENSHOTS.md).
Screenshot pending — add assets/img/report-coverage-gaps.png (see SCREENSHOTS.md).
Screenshot pending — add assets/img/report-mcdc-detail.png (see SCREENSHOTS.md).
Screenshot pending — add assets/img/export-picker.png (see SCREENSHOTS.md).
Screenshot pending — add assets/img/annotated-source.png (see SCREENSHOTS.md).Kod źródłowy z adnotacjami a zwykły kod źródłowy
Open Annotated Source zastępuje aktywną kartę kolorowym podglądem pokrycia dla tego pliku, w tej samej kolumnie; Open Annotated Source to the Side robi to samo, ale w podzielonym widoku, dzięki czemu kod źródłowy i widok z adnotacjami znajdują się obok siebie. Aby zamiast tego przełączać się w tym samym miejscu — przydatne na małym ekranie, gdzie podział czyni każdy panel zbyt wąskim — użyj Toggle Annotated Source: przełącza ona aktywną kartę między tymi dwoma widokami, zapamiętując, który z nich aktualnie oglądasz. Z poziomu samego widoku z adnotacjami Show Source przenosi od razu z powrotem do zwykłego edytora dla tego pliku.
To, jaki HTML faktycznie zobaczysz, zależy od externalHtmlReport.dir: gdy jest ustawiony i istnieje tam już strona odpowiadająca aktywnemu plikowi (llvm-cov układa strony per plik jako <nazwa-repo>/<ścieżka-względna>.html, więc folder nazwy repozytorium raportu nigdy nie wymaga konfiguracji), wyświetlana jest ta strona wygenerowana przez zestaw narzędzi zamiast wbudowanego renderera — jej lokalne linki/arkusz stylów są przepisywane, aby działały wewnątrz widoku webowego, i zawiera szczegóły, których wbudowany widok nie odtwarza (widoki rozwinięcia MC/DC, podświetlanie regionów, zestawienia katalogów). Brak pasującej strony dla tego pliku lub ustawienie pozostawione puste? Wtedy używany jest wbudowany renderer. Rozszerzenie tylko odczytuje ten katalog — nigdy do niego nie zapisuje.
Odznaka pokrycia do README
Generate Coverage Badge zapisuje do obszaru roboczego SVG w stylu shields dla aktywnego przebiegu — badge.outputPath, domyślnie coverage-badge.svg, względem folderu obszaru roboczego lub bezwzględnie, z tymi samymi zmiennymi co każde inne ustawienie ścieżki — i proponuje jego otwarcie. To zwykły plik w Twoim repozytorium, więc README osadza go bez żadnej usługi w tle, bez wycieczki do shields.io, i działa to także w repozytorium odciętym od sieci:

badge.metric wybiera, co pokazuje odznaka: lines (z etykietą coverage), branches, mcdc lub weighted, ten sam wynik złożony, który pokazuje pasek stanu, z etykietą score. Przebieg bez danych dla wybranej metryki dostaje szare n/a zamiast czerwonego 0%. Kolor podąża za Twoimi własnymi poziomami colorScale.*: lowColor poniżej lowThreshold, midColor do highThreshold, highColor od tego miejsca. Przy włączonym badge.autoUpdate odznaka jest przepisywana po każdym udanym wczytaniu, po cichu, a kanał wyjściowy odnotowuje każdy zapis jako [FUCINI_BADGE] — domyślnie wyłączone, bo zapisuje do obszaru roboczego przy każdym wczytaniu. Zatwierdź SVG razem z kodem, a obrazek na stronie repozytorium podąża za liczbą w edytorze.
{
"fuciniCoverage.badge.outputPath": "docs/coverage-badge.svg",
"fuciniCoverage.badge.metric": "weighted",
"fuciniCoverage.badge.autoUpdate": true
}
14. Historia i trendy
Włącz history.enabled, aby lokalnie zapisywać przebiegi (zachowując history.retention z nich). Otrzymasz wtedy strzałkę trendu (▲/▼) na pasku stanu, wykres trendu w widoku Coverage i dwa polecenia porównania: Compare with Last Run i Compare Two History Runs, z których każde tworzy różnicę regresji/poprawy per plik.
W Visual Studio. Każde wczytanie jest porównywane z poprzednim: trójkąt na marginesie przy każdym wierszu, który zaczął lub przestał być wykonywany (sinceLastRun.enabled), trend obok wyniku na pasku stanu i Compare with Last Run dla plików, których liczby się zmieniły. Z history.enabled uruchomienia są przechowywane pod %LOCALAPPDATA%\Fucini\CoverageStudio\history, w liczbie history.retention, więc porównanie przetrwa ponowne uruchomienie, wykres trendu ma co rysować, a Compare Two History Runs… wybiera dowolne dwa z nich.
Screenshot pending — add assets/img/history-compare.png (see SCREENSHOTS.md).
Screenshot pending — add assets/img/since-last-run.png (see SCREENSHOTS.md).Wykres trendu
Pod paskiem narzędzi widoku Coverage, przy dwóch zapisanych przebiegach lub więcej, pokrycie wierszy z historii jako linia, od najstarszego do najnowszego, ostatnich trzydzieści: kropka na przebieg, która po najechaniu podaje datę i wartość, a obok ostatnia wartość ze strzałką kierunku od pierwszego. Skala pionowa to własny zakres przebiegów, więc zespół na 92–94% widzi ruch, a nie płaską linię pod 100. Obie edycje rysują go z tej samej historii.
Screenshot pending — add assets/img/trend-chart.png (see SCREENSHOTS.md).
Sesje pokrycia
Jeden przebieg testów rzadko pokrywa wszystko, czego dotknęła zmiana: testy jednostkowe uruchomiono tu, zestaw integracyjny tam, a przejście przez interfejs z włączonym pokryciem gdzie indziej. Start Coverage Session zamienia kolejne wczytania w jedną sumę — każdy przebieg jest dodawany do poprzedniego wiersz po wierszu jako suma zbiorów, wiersz wykonany przez którykolwiek z nich jest pokryty, a liczniki się sumują — więc margines, drzewo i wynik pokazują, dokąd wszystkie razem dotarły. Przebieg na ekranie, jeśli jest, jest pierwszym w sesji. Pasek nad drzewem mówi, ile przebiegów i od kiedy, i kończy sesję; End Coverage Session robi to samo, a następne wczytanie znów stoi samodzielnie. W Visual Studio jedna pozycja w Tools → Coverage Studio rozpoczyna sesję, a zaznaczona — kończy ją.
Screenshot pending — add assets/img/coverage-session.gif (see SCREENSHOTS.md).
Linia bazowa CI: jak wypadam wobec main?
Compare with Last Run odpowiada, co zrobiła twoja ostatnia zmiana; przed pull requestem pytanie brzmi, jak wypadasz wobec main, a odpowiedź jest na serwerze kompilacji. baseline.report wskazuje raport publikowany przez kompilację gałęzi main, a każde wczytanie jest z nim porównywane: karta na pasku stanu niesie jednowierszową różnicę — vs CI baseline: 84.20% → 85.10% (+0.90%), 3 file(s) moved — a Compare with CI Baseline wymienia pliki, które się zmieniły, plik po pliku, tymi samymi słowami co Compare with Last Run. W Visual Studio polecenie jest w Tools → Coverage Studio i pobiera lub czyta raport, gdy o to poprosisz. Trzy sposoby wskazania go, w .vscode/settings.json:
- Adres URL serwowany przez CI. GitLab trzyma ostatnie artefakty zadania gałęzi pod stałym adresem; token pozostaje poza plikiem ustawień dzięki
${env:…}wremote.headers. Jenkins:https://jenkins.example.com/job/app/job/main/lastSuccessfulBuild/artifact/coverage/lcov.info. TeamCity:https://tc.example.com/repository/download/App_Main/.lastSuccessful/coverage/lcov.infozAuthorization: Bearer ${env:TC_TOKEN}. Adres URL jest pobierany i buforowany dokładnie tak, jak adres URL zcoverageFile.paths(ETag,remote.refreshMinutes). - Plik skopiowany przez pipeline na udział sieciowy — ścieżka bezwzględna, na przykład
\\build\drops\app\main\coverage.cobertura.xml. - Pobrany artefakt trzymany w folderze, powiedzmy
ci/main.lcov.info(wpisz ten folder do.gitignore) — ścieżka względna wobec folderu.
{
"fuciniCoverage.baseline.report": "https://gitlab.example.com/api/v4/projects/42/jobs/artifacts/main/raw/coverage/lcov.info?job=test",
"fuciniCoverage.remote.headers": ["PRIVATE-TOKEN: ${env:GITLAB_TOKEN}"]
}
Wystarczy dowolny format, który czytnik zna. Ścieżka, którą CI zapisało względem swojego checkoutu — src/Billing/Invoice.cs, tak jak Coverlet zapisuje ją na runnerze — jest przed porównaniem umieszczana pod tym folderem, aby spotkała plik, który rozwiązał lokalny przebieg; ścieżka bezwzględna z innej maszyny nie pasuje do niczego, więc niech pipeline zapisuje ścieżki względne. Linia bazowa, której nie da się pobrać ani odczytać, to wiersz w panelu Output, nigdy nieudane wczytanie.
Screenshot pending — add assets/img/ci-baseline.gif (see SCREENSHOTS.md).main.
Artefakt to zip, i on też jest czytany. GitHub i GitLab wydają artefakt jako archiwum, cokolwiek do niego włożono. Wskaż raport w archiwum po znaku #: element jest znajdowany po ścieżce albo po jej końcówce; bez # jest to jedyny plik archiwum albo jedyny, który wygląda na raport, a gdy jest ich kilka, panel Output je wymienia. To samo dotyczy pobranego zipa (ci/artifact.zip#lcov.info) oraz, w VS Code, adresu URL w coverageFile.paths. Token trafia do serwera, dla którego go ustawiono, i nigdzie dalej: przekierowanie do magazynu, który przechowuje archiwum, jest wykonywane bez niego.
{
"fuciniCoverage.baseline.report": "https://api.github.com/repos/acme/app/actions/artifacts/1234567/zip#coverage/lcov.info",
"fuciniCoverage.remote.headers": ["Authorization: Bearer ${env:GITHUB_TOKEN}"]
}
14a. Dla agentów AI: pokrycie widoczne na ekranie
Agent piszący testy potrafi je uruchomić i odczytać procent. Sam nie potrafi natomiast zapytać o to, co wie edytor: które wiersze tej funkcji nigdy się nie wykonały, która strona której gałęzi, które testy wykonują wiersz, czy diff, który właśnie napisał, jest pokryty. Sześć narzędzi odpowiada dokładnie na to, słowami, na podstawie których agent może działać, z wczytanego przebiegu — te same wykluczenia, to samo przemapowanie, te same liczby co na ekranie. Dzięki temu agent, któremu kazano pokryć luki w funkcji, i recenzent patrzący na margines mówią o tych samych wierszach.
| Narzędzie | Na co odpowiada |
|---|---|
coverage_summary | Sumy przebiegu dla każdej metryki oraz pliki najdalsze od pełnego pokrycia. Pierwsza rzecz, o którą warto zapytać. |
coverage_gaps | Co nigdy się nie wykonało w pliku, funkcji lub zakresie wierszy: niepokryte wiersze, niewzięte odnogi gałęzi, warunki MC/DC bez swojej pary, mutanty, które przeżyły. |
tests_for_line | Które testy wykonały wiersz, o ile raport to mówi — przebieg per test. |
patch_coverage | Pokrycie diffu — drzewa roboczego względem refa albo przekazanej łatki — i jego wiersze, które nigdy się nie wykonały. |
coverage_delta | Co się zmieniło od poprzedniego przebiegu: sumy oraz pliki, które zyskały lub straciły. |
test_run_command | Polecenie, które uruchamia testy tego obszaru roboczego z włączonym pokryciem. Agent je uruchamia; edytor sam wczytuje raport ponownie. |
Własny agent VS Code ma je jako narzędzia, bez żadnej konfiguracji. Wszyscy pozostali agenci — każdy klient obsługujący MCP, czyli Model Context Protocol — korzystają z nich przez serwer, który edytor uruchamia, gdy włączone jest mcp.enabled, tak samo w VS Code jak w Visual Studio. Copy MCP Server Configuration umieszcza wpis dla klienta w schowku, w postaci, w jakiej VS Code i Visual Studio czytają go z mcp.json; klient, który zewnętrzny klucz nazywa mcpServers, przyjmuje ten sam wpis pod tą nazwą.
Screenshot pending — add assets/img/mcp-config.png (see SCREENSHOTS.md).
Screenshot pending — add assets/img/vs-mcp-config.png (see SCREENSHOTS.md).{
"servers": {
"fucini-coverage": {
"type": "http",
"url": "http://127.0.0.1:39217/mcp",
"headers": { "Authorization": "Bearer …" }
}
}
}
- Jest wyłączony, dopóki go nie włączysz, i nasłuchuje tylko na
127.0.0.1: nic spoza tego komputera do niego nie dotrze. - Wywołanie musi zawierać twój token, utworzony raz i przechowywany dla ciebie; bez niego odpowiedzią jest 401. Skopiowana konfiguracja zawiera token: trzymaj ją poza repozytorium.
- Wywołanie wysłane przez stronę internetową — mówi o tym jego
Origin— jest odrzucane, cokolwiek zawiera. - Czyta wczytany przebieg i niczego nie zapisuje. Przebieg testów jest wskazywany, nie uruchamiany: agent uruchamia polecenie we własnym terminalu.
Port to mcp.port, 39217, jeśli nie ustawiono innego. Gdy jest zajęty — drugie okno, druga edycja obok tej — używany jest następny wolny, a skopiowana konfiguracja wskazuje ten, który działa. Panel Output mówi, gdzie serwer nasłuchuje ([FUCINI_MCP]) i dlaczego nie mógł ([FUCINI_MCP_001]). To, czego plan nie obejmuje — nazwy testów, szczegóły MC/DC — narzędzia zliczają, nie wymieniając tego, tak jak podpowiedź po najechaniu.
15. Referencja poleceń
W Visual Studio. Każde polecenie jest w Tools → Coverage Studio, nazwane jak w tabeli bez prefiksu Fucini Coverage:; pasek narzędzi okna Coverage i menu prawego przycisku na wierszu mają te, które tam należą, a menu prawego przycisku w oknie kodu ma trzy, które działają na edytorze: Run This Test with Coverage, Show Tests That Ran This Line i Exclude Selection from Coverage. Te z klawiszami to dwuklawiszowe akordy po Ctrl+Shift+U: R przeładowuje, N i P idą do następnego i poprzedniego niepokrytego wiersza, B do następnej częściowo przetestowanej decyzji, T wypisuje testy, które wykonały wiersz, X wyklucza zaznaczenie — nie Alt+N z VS Code, bo w Visual Studio Alt z literą otwiera menu. Zmień je w Tools → Options → Keyboard, gdzie są wymienione jako Coverage Studio: …. Nie w tej edycji: panel Test Coverage to API VS Code — uruchomienie jest zamiast tego w oknie Coverage — a Solution Explorer nie może pokazywać odznak. Tylko w tej edycji: Run Native Project with Coverage, dla startowego projektu C++.
W Visual Studio: gdzie co jest. Okno Coverage znajduje się pod View → Other Windows → Coverage, a jako pierwsze także pod Tools → Coverage Studio, gdzie jest każde polecenie tej edycji, w grupach: wczytywanie i ponowne wczytywanie, obserwowanie pliku, dwa polecenia kopiowania i karty; Run Tests with Coverage, Run Native Project with Coverage i Collect Coverage in Test Explorer…; Next i Previous Uncovered oraz decyzje przetestowane częściowo; kolorowanie, liczniki wykonań i tryby marginesu; źródło pokrycia pliku, testy, które wykonały wiersz, jeden test z pokryciem, dwa sposoby wykluczania; Compare with Last Run, Compare Two History Runs…, Compare with CI Baseline, sesja pokrycia i Check Coverage Thresholds; grupa Reports — Show Annotated Source, Open HTML Report, Generate Full HTML Report, Export Coverage Report… i Generate Coverage Badge; potem Getting Started, progi zgodności i Licence…. Własny pasek narzędzi okna ma pięć najczęściej używanych: Load Coverage, Reload, Toggle Coverage Painting, Copy Coverage Summary i progi zgodności; pod nimi perspektywa, filtr i sortowanie oraz pole wyszukiwania; pod tymi trend. Zatrzymaj wskaźnik na wierszu drzewa i naciśnij jego ⋯, aby otworzyć menu wiersza — otwórz plik, otwórz jego folder, skopiuj ścieżkę, bezwzględną lub względną, z dowolnym rodzajem ukośnika, wyklucz go z pokrycia. Po prawej stronie paska stanu są wynik uruchomienia i wynik otwartego pliku, z trendem od ostatniego uruchomienia; Show Coverage Card i Show Coverage Card for This File otwierają karty z liczbami, te same, które VS Code pokazuje, gdy wskaźnik zatrzyma się na jego elemencie paska stanu.







Screenshot pending — add assets/img/statusbar-and-toolbar.gif (see SCREENSHOTS.md).
Screenshot pending — add assets/img/statusbar-menu.png (see SCREENSHOTS.md).
Screenshot pending — add assets/img/worst-functions.png (see SCREENSHOTS.md).| Polecenie | Działanie |
|---|---|
| Load Coverage | Wykryj i wczytaj pokrycie dla obszaru roboczego. Domyślnie Alt+Shift+R (Ctrl+Alt+R w macOS). |
| Pick Coverage File | Wybierz pliki śladu — jeden, kilka lub za każdym razem kolejny; wybory się sumują, są scalane i zapisywane do coverageFile.paths, więc odtąd wczytują się same. |
| Show Loaded Coverage Files | Wypisz pliki śladu aktywnego przebiegu. Widok Pokrycie też je wypisuje, każdy z przyciskiem wyładowania i przyciskiem wyboru obok. |
| Toggle Tracefile Watch | Obserwuj zmiany plików śladu i przeładowuj automatycznie. |
| Run Tests with Coverage | Rozpoznaj program uruchamiający testy, uruchom go z pokryciem w zadaniu terminala, wczytaj to, co zapisze, i zaproponuj dodanie ścieżki do ustawień. |
| Run This Test with Coverage | Test pod kursorem — metoda, klasa lub blok describe, albo plik — uruchomiony przepisem zawężonym do niego, potem wczytany jak każdy przebieg. Także w menu kontekstowym edytora. |
| Show Tests That Ran This Line | Tam, gdzie raport mówi, które testy co wykonały, wypisz testy, które wykonały wiersz pod kursorem, najaktywniejsze najpierw, i otwórz wybrany tam, gdzie jest zapisany. |
| Run Tests Affected by My Changes… | Wypisz testy, które wykonały wiersz zmieniany przez drzewo robocze względem testImpact.baseRef, otwórz wybrany albo uruchom tylko te testy, jeśli raporty pochodzą z przebiegu per test. |
| Show Minimal Test Set… | Najmniej testów, które nadal wykonują każdy wiersz wykonywany przez zestaw, a potem testy, które nie dodają żadnego własnego wiersza. |
| Run App with Coverage… | Uruchom aplikację .NET z folderu pod dotnet-coverage i po jej zamknięciu wczytaj to, co w niej odwiedzono. |
| Run Mutation Tests Here | Zmutuj funkcję, w której stoi kursor — albo zaznaczenie, albo plik — za pomocą Stryker.NET, StrykerJS lub PIT i wczytaj raport obok pokrycia na ekranie. |
| Exclude This File from Coverage / Exclude from Coverage | Wpisz otwarty plik — albo, na wierszu widoku Coverage, plik lub /** folderu — do fuciniCoverage.ignore w ustawieniach folderu, jednorazowo. |
| Exclude Selection from Coverage | Zapisz wykluczenie tam, gdzie jest kod: [ExcludeFromCodeCoverage] nad składową .NET, LCOV_EXCL_LINE w jednym wierszu, LCOV_EXCL_START/STOP wokół kilku, znakiem komentarza właściwym plikowi. Także z żarówki i menu kontekstowego edytora. |
| Start Coverage Session / End Coverage Session | Gdy sesja trwa, każde wczytanie jest dodawane do poprzedniego jako suma; pasek nad drzewem liczy przebiegi i kończy ją. |
| Next / Previous Uncovered | Przechodź między niepokrytymi regionami. Domyślnie Alt+N / Alt+P (Ctrl+Alt+N / Ctrl+Alt+P w macOS). |
| Choose Editor Gutter Mode... | Wyłączone, paski tylko na niepokrytych wierszach, paski czerwono-bursztynowo-zielone albo mapa cieplna liczby trafień na marginesie edytora. |
| Cycle Editor Gutter Mode | Jeden krok dalej przez off, uncovered, coverage i heatmap — Alt+G lub przycisk trybu na pasku stanu. |
| Choose Coverage Source for This File... | Gdy otwarty plik mierzy więcej niż jeden wczytany raport, wybierz, z którego pochodzą jego liczby — dla pliku, jego folderu lub wzorca; zapisuje regułę coverageFile.sources. |
| Clear Coverage Source for This File... | Usuń reguły coverageFile.sources, które dotyczą otwartego pliku. |
| Toggle Inline Hit Counts | Pokaż lub ukryj liczniki wykonań ×N za każdym wierszem — przełącza hitCounts.inline. |
| Show in Test Coverage View | Opublikuj aktywny przebieg do własnego panelu Test Coverage VS Code (nawet przy wyłączonym testCoverage.publish) i otwórz go. |
| Suggest Path Remap Rule | Wywiedź regułę pathRemap, która dopasowałaby niedopasowane pliki aktywnego przebiegu do obszaru roboczego, i zaproponuj jej dodanie. |
| What Community Includes | Każdy limit i każda wstrzymana funkcja darmowego poziomu na jednej liście, z informacją, ile każdego limitu zużyto. |
| Open HTML Report | Otwórz wygenerowany raport statyczny. |
| Generate Full HTML Report | Zbuduj raport wielostronicowy. |
| Open Annotated Source / …to the Side | Widok pokrycia z adnotacjami dla pliku. |
| Toggle Annotated Source | Przełącz między źródłem a widokiem adnotowanym. Domyślnie Alt+A (Ctrl+Alt+A w macOS). |
| Show Worst-Covered Files / Folders / Functions | Quick Pick uporządkowany od najniższego. |
| Copy Uncovered Lines | Podsumowanie w Markdown każdego niepokrytego zakresu. |
| Compare Two History Runs / with Last Run | Różnica regresji dla każdego pliku — dwa przebiegi zachowane w historii albo przebieg na ekranie wobec tego, który zastąpił. |
| Compare with CI Baseline | Wczytany przebieg wobec raportu wskazanego w baseline.report — raportu gałęzi main z CI, adresu URL lub pobranego artefaktu — plik po pliku. |
| Show Indirect Coverage Changes… | Wiersze, których pokrycie się zmieniło, choć nikt ich nie edytował, względem linii bazowej CI albo poprzedniego przebiegu, per plik. |
| Check Coverage Thresholds | Oceń bramki zgodności. |
| Export Fucini JSON | Wyeksportuj bieżący przebieg jako Fucini JSON. |
| Export Coverage Report... | Wybierz format — CSV, Markdown, LCOV, XML Cobertura, SARIF lub odznakę SVG — i miejsce docelowe. |
| Generate Coverage Badge | Zapisz odznakę SVG aktywnego przebiegu do badge.outputPath, pokazującą badge.metric, i zaproponuj jej otwarcie. |
| Copy MCP Server Configuration | Umieść w schowku to, czego klient MCP potrzebuje, by pytać o pokrycie na ekranie — adres serwera i twój token; gdy serwer jest wyłączony, zaproponuj jego włączenie. |
| Show Status Bar Menu | Otwórz menu szybkich akcji. |
| Browse for External HTML Report / Full Report Output Dir… | Ustaw katalogi raportów za pomocą selektora. |
16. Referencja ustawień
Kompletna, skategoryzowana tabela ustawień — każda opcja z wartością domyślną — znajduje się na stronie Funkcje i ustawienia. Wszystkie klucze mają prefiks fuciniCoverage..
Warto zaznaczyć: fuciniCoverage.language ustala własny interfejs działania tego rozszerzenia (pasek stanu, powiadomienia, podpowiedzi, widoki webowe) na konkretny język, niezależnie od języka wyświetlania VS Code — domyślnie auto, z pakietami dla wszystkich 18 obsługiwanych języków. Nie zmienia to pozycji w palecie poleceń ani etykiet w ustawieniach, które VS Code nadal pobiera z własnego języka wyświetlania.
W Visual Studio. Te same klucze fuciniCoverage.*, czytane z maksymalnie czterech plików, przy czym późniejszy wygrywa: własne ustawienia użytkownika VS Code, jeśli VS Code jest na maszynie — czytane, nigdy nie zapisywane, żeby Twoje kolory i progi przeszły razem; %APPDATA%\Fucini\CoverageStudio\settings.json, ustawienia użytkownika tej edycji; .vscode\settings.json w folderze lub obok rozwiązania, więc repozytorium skonfigurowane dla VS Code jest skonfigurowane dla Visual Studio; oraz fucini-coverage.json w katalogu głównym rozwiązania, dla zespołu, który wolałby nie trzymać folderu .vscode w repozytorium .NET — edycja VS Code też go czyta. Zębatka na pasku narzędzi okna Coverage otwiera okno ustawień, które zapisuje plik użytkownika albo ten plik folderu, który istnieje, jak mówi jego wybór Write changes to, i zachowuje komentarze edytowanego pliku. fuciniCoverage.language działa tam tak samo; menu podążają za własnym językiem Visual Studio.
17. Kody błędów
Diagnostyka trafia do kanału wyjściowego Fucini Coverage (View → Output → Fucini Coverage), każda ze stałym kodem FUCINI_*.
W Visual Studio. Te same kody trafiają do panelu Fucini Coverage okna Output (View → Output) i są zachowywane w %LOCALAPPDATA%\Fucini\CoverageStudio\coverage-studio.log, na pytanie, które przychodzi po zamknięciu IDE. Trzy, które się zdarzają: nic nie jest oznaczone, choć panel mówi, że pliki zostały wczytane — tryb marginesu to off, wybierz Show Coverage in Editor; FUCINI_REMAP_001 i pasek informacyjny — raport wymienia ścieżki, których tu nie ma, a panel proponuje regułę pathRemap; okno Coverage mówi, że potrzebuje WebView2 — zainstaluj Microsoft Edge WebView2 Runtime, znaczniki w edytorze go nie potrzebują.
| Kod | Znaczenie |
|---|---|
FUCINI_PARSE_001 | Nieobsługiwany/nierozpoznany format pokrycia — żaden parser nie pasował do pliku. |
FUCINI_PARSE_010 | Plik lcov nie zawierał rekordów SF. |
FUCINI_PARSE_020 | JSON llvm-cov nieprawidłowy, brak data[] lub brak plików. |
FUCINI_PARSE_030 | Brak korzenia Cobertura <coverage> lub nieprawidłowy XML. |
FUCINI_PARSE_040 | Brak korzenia JaCoCo <report> lub brak plików źródłowych. |
FUCINI_PARSE_050 | JSON Istanbul/SimpleCov nieprawidłowy lub bez plików. |
FUCINI_PARSE_060 | JSON SimpleCov nieprawidłowy lub brak tablicy files najwyższego poziomu. |
FUCINI_PARSE_070 | Profil Go bez nagłówka mode: albo bez bloków pokrycia. |
FUCINI_PARSE_080 | Brak korzenia Clover <coverage> lub <project> albo brak plików w środku. |
FUCINI_PARSE_090 | Brak korzenia OpenCover <CoverageSession> albo brak plików w środku. |
FUCINI_PARSE_100 | JSON coverage.py jest nieprawidłowy albo brakuje obiektu files najwyższego poziomu. |
FUCINI_PARSE_110 | JSON gcov/gcovr jest nieprawidłowy albo brakuje tablicy files najwyższego poziomu. |
FUCINI_PARSE_120 | XML GNATcoverage bez elementu <source> albo index.xml, którego xi:include nigdy nie rozwinięto — wczytaj zamiast tego pliki *.xml dla poszczególnych źródeł. |
FUCINI_PARSE_130 | Brak elementu głównego <BullseyeCoverage> albo nie zawiera on elementów <src>. |
FUCINI_PARSE_140 | Brak elementu głównego <CoverageDSPriv>, brak tabeli <SourceFileNames> do rozwiązania wierszy albo brak danych o wierszach. |
FUCINI_PARSE_150 | Nieprawidłowy JSON pokrycia Xcode lub brak tablicy targets najwyższego poziomu. |
FUCINI_PARSE_160 | Brak elementu głównego <coverage> SonarQube albo nie zawiera on elementów <file>. |
FUCINI_PARSE_170 | Nieprawidłowy JSON Coveralls lub brak tablicy source_files najwyższego poziomu. |
FUCINI_LOAD | Wczytanie anulowano z jego powiadomienia o postępie; poprzedni przebieg, jeśli był, pozostaje wczytany. |
FUCINI_REMOTE_001 | Nie udało się pobrać adresu URL z coverageFile.paths, z powodem; zamiast tego wczytywana jest ostatnia pobrana kopia. Zwykłe wiersze [FUCINI_REMOTE] odnotowują każde pobranie i każde sprawdzenie bez zmian (304). |
FUCINI_REMOTE_002 | Adres URL z coverageFile.paths nie dał pełnej odpowiedzi w ciągu 30 sekund — najczęściej proxy lub VPN, które przyjmuje połączenie i potem milczy; zamiast tego wczytywana jest ostatnia pobrana kopia. |
FUCINI_REMOTE_003 | Adres URL z coverageFile.paths odpowiedział stroną HTML zamiast plikiem śladu — najpewniej stroną logowania. Strona nie jest buforowana, zamiast niej wczytywana jest ostatnia pobrana kopia; sprawdź token w remote.headers. |
FUCINI_REMAP_002 | Zaproponowano regułę pathRemap dla ścieżek, które po wczytaniu zostały niedopasowane, z liczbą tych, które wyjaśnia — albo nie udało się żadnej wywieść, albo wywiedziona reguła jest już w ustawieniu i ich nie rozwiązała. |
FUCINI_REMAP_003 | Zaproponowana reguła została dopisana do fuciniCoverage.pathRemap przez Apply Suggested Remap, a pokrycie jest przeładowywane. |
FUCINI_GITDIFF_001 | Rozszerzenie Git jest niedostępne; pokrycie diffa jest pomijane i pokazywany jest cały przebieg. |
FUCINI_GITDIFF_002 | gitDiff.baseRef zaczyna się od -, od czego żadna referencja git zacząć się nie może (git odczytałby to jako opcję); pokrycie diffa jest pomijane i pokazywany jest cały przebieg. |
FUCINI_IGNORE | Ile plików fuciniCoverage.ignore pominęło w przebiegu i które. |
FUCINI_UNMEASURED_001 | Pliki rodzaju przebiegu, których żaden test nie wczytał, po jednym w wierszu. |
FUCINI_UNMEASURED_002 | Ponad 5 000 plików obszaru roboczego pasowało do jednego z rozszerzeń przebiegu; do listy Unmeasured rozważono tylko pierwsze 5 000. |
FUCINI_UNMEASURED_003 | W trybie count niektóre niezmierzone pliki są wymienione, ale nie policzone: osiągnięto limit odczytu (2 000 plików lub 50 MB na wczytanie). |
FUCINI_UNMEASURED_004 | Nie udało się odczytać niezmierzonego pliku; jest wymieniony, ale nie policzony. |
FUCINI_TESTCOVERAGE | Ile plików opublikowano do widoku Test Coverage VS Code. |
FUCINI_BADGE | Odznaka została zapisana, z jej ścieżką, etykietą i wartością. |
FUCINI_BADGE_001 | Nie udało się zapisać odznaki, z powodem. |
FUCINI_WORKSPACE | Folder został dodany do obszaru roboczego lub z niego usunięty; pokrycie jest wykrywane ponownie. |
FUCINI_VARIABLES | Co odpowiedziało każde ${command:…} w ustawieniach ścieżek albo dlaczego zostało w zapisanej postaci: polecenie zawiodło, nie zwróciło nic użytecznego lub obszar roboczy nie jest zaufany. |
FUCINI_WATCH | Co robi obserwator: obserwowane ścieżki, skonfigurowany plik, który się pojawił, zadanie wymienione w watch.reloadAfterTasks, które się zakończyło (z kodem wyjścia) i wyzwoliło przeładowanie, albo ścieżka pod files.watcherExclude, która zamiast tego jest odpytywana. |
18. Prywatność
Telemetrią steruje ustawienie telemetry.enabled o zasięgu window. Domyślnie jest wyłączona. Dzienne podsumowanie i powiadomienie o usunięciu wymagają ponadto, aby globalne telemetry.telemetryLevel VS Code zezwalało na telemetrię; sygnał instalacji i kilka drobnych zdarzeń są wysyłane niezależnie od tego, podobnie jak wpis w rejestrze użycia instalacji korzystającej z wersji próbnej lub bezpłatnego poziomu Community. Na poziomie Community polecenie Unlock Full Features wymienia tę telemetrię na wszystkie funkcje Pro, w tym MC/DC, na 30 dni, raz na maszynę — wyłącz ją ponownie, a obowiązuje standardowy zestaw Community; licencji płatnej nie dotyczy to w żadnym przypadku. Co jest wysyłane, opisano w polityce prywatności.
Dwie rzeczy warto znać, bo możesz coś z nimi zrobić. Pierwsza to Twój identyfikator rejestru użycia: w okresie próbnym i na poziomie Community rozszerzenie pokazuje go w Show License / Activation oraz na dole What Community Includes, gdzie wybranie wiersza kopiuje go i otwiera politykę prywatności. Rejestr zna Twoją maszynę wyłącznie po skrócie i po niczym więcej, więc ten identyfikator jest jedynym sposobem, by zapytać, co rejestr o Tobie zawiera, kazać to usunąć albo wnieść sprzeciw — podaj go, a znajdziemy Twój wiersz; bez niego nie możemy. Druga to wpis instalacji: jeden wiersz zapisywany przy pierwszym zgłoszeniu instalacji i przechowywany, zamiast usuwany po 90 dniach, zawierający identyfikator instalacji, dzień, miejsce, na które rozwiązano adres, wersje oraz system operacyjny — nie sam adres i nic o Twoim kodzie. To dzięki niemu możemy powiedzieć, ile instalacji było przez te lata. Oba są w pełni opisane w polityce prywatności i oba zostaną usunięte, jeśli o to poprosisz.

19. Ewaluacja i aktywacja
Fucini Coverage Studio jest dystrybuowane jako ewaluacyjna wersja przedpremierowa. Przy pierwszym uruchomieniu poprosimy o zgodę na jej ocenianie i rozpocznie się okres próbny — wszystkie funkcje są dostępne przez 14-dniowy okres próbny, liczony od pierwszego użycia na danej instalacji. Nie ma stałej daty, po której cokolwiek przestaje działać.
Od wersji 2.2026.2 okres próbny nowej instalacji zaczyna się, gdy tylko rozszerzenie raz połączy się z serwerem licencji; do tego czasu działa na poziomie Community i o tym informuje. W kontenerze deweloperskim lub Codespace okres próbny się nie zaczyna — pełny zestaw odblokowuje tam kod subskrypcji, klucz lub 7-dniowa przepustka.
Gdy okres próbny się kończy, nic nie zostaje zablokowane: rozszerzenie przechodzi na bezpłatny poziom Community. Aby odzyskać pełny zestaw, aktywuj — aktywacja łączy się z serwerem licencji i automatycznie stosuje zwrócony klucz, bez e-maila i bez klucza do ręcznego przepisywania:
Screenshot pending — add assets/img/licence-dialog.png (see SCREENSHOTS.md).- Uruchom
Fucini Coverage: Show License / Activation(dostępne również z paska stanu po wygaśnięciu okresu próbnego lub klucza) i kliknij Request License… (lub Request Renewed Key…, jeśli aktywowałeś wcześniej). - Potwierdź żądanie. Klucz jest wydawany automatycznie, a Twoje dane kontaktowe z wcześniejszego żądania są używane ponownie zamiast pytania o nie po raz kolejny.
- To wszystko. Klucz aktywacyjny jest generowany i automatycznie zapisywany w
fuciniCoverage.license.key. Pasek stanu po chwili przełącza się z okresu próbnego na aktywowaną licencję.
Ręczna droga na jednym obrazku: otwórz panel licencji, wybierz Enter Key, wklej klucz z wiadomości e-mail, a baner zmienia się na „Activated”.
Screenshot pending — add assets/img/activate-key.gif (see SCREENSHOTS.md).Jeśli automatyczne żądanie kiedykolwiek zawiedzie (brak połączenia, problem z serwerem): uruchom Fucini Coverage: Copy Activation Request Code, wyślij kod przez stronę kontaktową lub na info@fucini.consulting, a otrzymany klucz FCK1.… wklej poleceniem Fucini Coverage: Enter Activation Key (lub bezpośrednio do settings.json):
{ "fuciniCoverage.license.key": "FCK1.…wklej cały klucz…" }Nazwa ustawienia to fuciniCoverage.license.key (zakres użytkownik/globalny). Klucz jest powiązany z Twoją maszyną i użytkownikiem systemu operacyjnego, może mieć termin ważności i może włączać lub ograniczać poszczególne funkcje oraz limitować liczbę wczytań pokrycia dziennie. Jeśli pojawi się komunikat „invalid for this machine”, poproś o nowy klucz z tej instalacji — klucz wydany dla innej maszyny nigdy nie zostanie tu uznany za ważny.
W Visual Studio. W tej edycji nie ma darmowego poziomu: bez subskrypcji nic nie jest czytane. Z subskrypcją plan rozstrzyga tam o tym samym, o czym rozstrzyga w VS Code — funkcja, której plan nie obejmuje, jest wstrzymana, a jej polecenie mówi o tym, zamiast się wykonać. Tam również obowiązuje najstarsza wersja, którą serwer licencji jeszcze obsługuje: build starszy od niej dostaje raz dziennie informację z datą, w której przestanie działać, i do tego dnia działa dalej. Praca offline nigdy nie zatrzymuje builda.
Darmowy poziom Community: tygodniowy limit
Community nigdy nie przestaje pokazywać pokrycia. Marginesy, linijka przeglądu, podpowiedzi po najechaniu, CodeLens, widok Coverage, tryb obserwowania, pokrycie zmian (diff) i historia nie są w ogóle liczone, a wczytywanie pliku śledzenia poleceniem jest ograniczone jedynie do 25 dziennie. Limitowany jest wynik: po pięć razy w tygodniu — otwarcie raportu HTML, eksport, porównanie dwóch przebiegów, sprawdzenie progów i podgląd kodu z adnotacjami w miejscu.
Tydzień jest twój, nie kalendarzowy: zaczyna się przy pierwszym użyciu i kończy siedem dni później. Gdy limit zostanie wykorzystany, komunikat podaje nazwę czynności i dzień, w którym limit wróci, a po tym jednym komunikacie wspomina o tym już tylko pasek stanu. Fucini Coverage: What Community Includes wyświetla każdy limit wraz z tym, ile wykorzystano i kiedy się odnowi — zanim w ogóle do któregoś dojdziesz.
Screenshot pending — add assets/img/weekly-allowance.png (see SCREENSHOTS.md).
Screenshot pending — add assets/img/community-limit-prompt.png (see SCREENSHOTS.md).
Screenshot pending — add assets/img/community-includes-weekly.png (see SCREENSHOTS.md).Trzy szczegóły należą do planów płatnych, a same ustalenia pozostają darmowe: Community oznacza każdą linię, która ma mutanty, które przeżyły, i podaje ich liczbę, ale nie to, co każdy mutant zmienił; podaje, ile testów wykonało linię, ale nie ich nazwy; pokazuje też Max CRAP przebiegu, ale nie rankingową listę Riskiest Methods.
Screenshot pending — add assets/img/mutant-hover-community.png (see SCREENSHOTS.md).Jeśli używasz Community od czasu sprzed wprowadzenia tygodniowego limitu (0.2026.83), twoje dotychczasowe limity obowiązują jeszcze przez 30 dni; informacja o tym pojawia się raz, z podaniem daty. Liczniki są przechowywane na twoim komputerze — we własnym magazynie VS Code oraz w ~/.fucini-coverage/, więc nowy profil VS Code kontynuuje ten sam tydzień — i nigdy nie są nigdzie wysyłane.
Karnet 7-dniowy
Subskrypcja to jeszcze nie ten moment? Karnet 7-dniowy to wszystko z Pro na jeden tydzień, opłacone raz: nic się nie odnawia i niczego nie trzeba anulować. Kupisz go na stronie z cennikiem (komunikat o limicie Community ma do tego przycisk), a kod aktywacyjny przyjdzie e-mailem.
Screenshot pending — add assets/img/pricing-week-pass.png (see SCREENSHOTS.md).- Uruchom
Fucini Coverage: Enter Subscription Code— polecenie jest dostępne zarówno w edycji Community, jak i w Pro. - Wybierz Pro i wklej kod
FCB1-…z wiadomości e-mail. - To wszystko. Klucz zostanie wystawiony i zastosowany za ciebie i działa offline. Tydzień liczy się od płatności, więc aktywuj karnet od razu po zakupie. Gdy tydzień minie, rozszerzenie samo wróci do Community i nadal będzie pokazywać pokrycie.
Screenshot pending — add assets/img/pass-step-plan.png (see SCREENSHOTS.md).
Screenshot pending — add assets/img/pass-step-code.png (see SCREENSHOTS.md).W Visual Studio. Ten sam kod aktywuje Fucini Coverage Studio dla Visual Studio, 2022 i 2026: otwórz Tools → Coverage Studio → Licence…, wklej kod, wybierz plan, którego dotyczy, i naciśnij Activate. Okno Coverage pokazuje wtedy Activated nad drzewem; rozwinięty strzałką wiersz pokazuje datę, do której klucz jest ważny, oraz przycisk do Twojego konta. Jedna maszyna to jedno miejsce: aktywuj VS Code albo Visual Studio, a drugi edytor na tej samej maszynie podąży sam — Visual Studio czyta klucz VS Code, a VS Code klucz Visual Studio — więc niczego nie wpisuje się dwa razy i nie zajmuje się drugiego miejsca. Oba utrzymują klucz tak samo: Pro Plus, Business i Enterprise meldują się dwa razy dziennie, a klucz Pro jest odnawiany w tygodniu przed wygaśnięciem.


Przejście na nowy komputer i zarządzanie stanowiskami
Klucz jest przypisany do jednej maszyny, więc nowy komputer wymaga nowego — a subskrypcja opłaca tylko tyle maszyn, ile deklaruje. Zwolnij starą samodzielnie: zaloguj się w zarządzaniu subskrypcją, znajdź stanowisko, którego już nie używasz, wybierz Free up i aktywuj nową maszynę tym samym kodem. Zakup Pro nie wysyła Ci hasła — konto istnieje, po prostu jeszcze go nie ma, więc za pierwszym razem użyj ustaw lub zresetuj hasło z adresem, którym subskrybowałeś.
W planach Business i Enterprise zapraszasz każdą osobę e-mailem z tej samej strony. Każdy dostaje kod aktywacyjny tylko dla siebie, a gdy go użyje, jego adres pojawia się przy jego stanowisku — kiedy ktoś odchodzi, widzisz, które było jego, i zwalniasz je dla następnej osoby. Zaproszenie zajmuje stanowisko od chwili wysłania i wygasa po 14 dniach, jeśli pozostanie nieużyte; wycofaj je, aby natychmiast odzyskać miejsce.
Testowanie wersji przedpremierowych
Nowości trafiają na fucini.software, zanim trafią do Marketplace, a Ty możesz poprosić, by Ci je proponowano. Otwórz widok Coverage, rozwiń panel licencji i naciśnij Testuj wersje przedpremierowe… — albo ustaw fuciniCoverage.update.preRelease. Od tej chwili rozszerzenie sprawdza tutaj osobny kanał przedpremierowy obok zwykłego i proponuje nowszą z dwóch wersji.
Screenshot pending — add assets/img/licence-prerelease.png (see SCREENSHOTS.md).Wersje przedpremierowe są przetestowane, ale to kompilacje, których jesteśmy najmniej pewni — zgłaszasz się, by znaleźć to, co nam umknęło. Dołączenie mówi nam, że ta instalacja jest w kanale, więc wiemy, ile osób testuje, i możemy powiedzieć, co się zmieniło; po wyjściu następne stabilne wydanie wraca Cię na zwykłą ścieżkę. Nie zawsze jest dostępna wersja przedpremierowa, a dołączenie, gdy jej nie ma, nic nie kosztuje: rozszerzenie znajduje pusty kanał, nic o tym nie mówi i nadal proponuje wydania stabilne, dopóki jakaś się nie ukaże.
Screenshot pending — add assets/img/licence-prerelease-joined.png (see SCREENSHOTS.md).20. Kontakt i licencja
Pytania, zgłoszenia błędów lub alternatywne warunki licencyjne — zobacz stronę kontaktową lub wyślij e-mail na info@fucini.consulting. Licencjonowane na warunkach MIT z warunkiem atrybucji w notatkach wydania; zobacz również Notice.
21. W wierszu poleceń
Czytnik działa także bez edytora: npm install -g fucini-coverage, za darmo, w systemach Windows, Linux, WSL i macOS. fucini-coverage check coverage/lcov.info --lines 80 to bramka, na której potok kończy się błędem; summary, export, report, badge i compare robią to, co polecenia edytorów o tych nazwach, a mcp serwuje sześć narzędzi z sekcji powyżej agentowi na serwerze. Czyta fucini-coverage.json, plik ustawień, który czyta edycja dla Visual Studio, więc progi ustawia się raz. fucini-coverage help <command> objaśnia każde z nich; pełna strona to fucini-coverage w npm.
Screenshot pending — add assets/img/cli-demo.gif (see SCREENSHOTS.md).