1. מבוא
Fucini Coverage Studio הופך את קובצי עקבות הכיסוי שה-build שלכם כבר מייצר לכיסוי מלא בתוך העורך — ב-VS Code וב-Visual Studio. הוא קורא עשרים וחמישה פורמטים, מנרמל אותם למודל Fucini קנוני אחד, ממזג ריצות מרובות באופן דטרמיניסטי ומציג את התוצאה בעורך עצמו — שוליים, CodeLens, ריחוף ותצוגת Covered Files — כך שאין מציג נפרד שבשבילו צריך לעזוב את העורך. שתי המהדורות חולקות קורא אחד: אותו דוח נותן את אותם מספרים, עד הספרה, בשתיהן. מדריך זה נכתב מנקודת המבט של VS Code; היכן ש-Visual Studio שונה, תיבת In Visual Studio אומרת כיצד.
הוא נבנה מתוך מחשבה על תהליכי עבודה של בטיחות פונקציונלית: כיסוי MC/DC, כיסוי אזורים ומופעי C++, ציון מורכב משוקלל לפי בטיחות, ופסק דין COMPLIANT / NON-COMPLIANT הניתן להגדרה, המותאם לחשיבה של IEC 61508, ISO 26262 ו-DO-178C.
Screenshot pending — add assets/img/marketplace-demo.gif (see SCREENSHOTS.md).2. התקנה ודרישות
- VS Code ≥ 1.88 — הגרסה המינימלית שהתוסף תומך בה — או Visual Studio 2022 או 2026, Community, Professional או Enterprise (ראו את התיבה למטה).
- קובץ עקבות כיסוי שהפרויקט שלכם כבר מייצר (ראו §4).
התקינו מה-Marketplace, או מקובץ .vsix דרך Extensions → ⋯ → Install from VSIX…. התוסף מופעל בעת ההפעלה ומוסיף סמל Coverage לשורת הפעילות.
ב-Visual Studio. אותו מוצר יוצא כתוסף שני, Fucini Coverage Studio ל-Visual Studio, עבור Visual Studio 2022 ו-2026 — Community, Professional ו-Enterprise. הוא אינו משתמש בכיסוי הקוד של Visual Studio עצמו: ב-Visual Studio 2022 זו תכונה של Enterprise, כך שב-Community וב-Professional זהו הכיסוי היחיד שה-IDE יציג. התקינו את ה-.vsix על ידי פתיחתו — ה-VSIX Installer שואל איזה Visual Studio — או דרך Extensions → Manage Extensions; התוסף נטען כשנפתחים פתרון או תיקייה. חלון Coverage זקוק ל-Microsoft Edge WebView2 Runtime, ש-Windows 11 ו-Visual Studio 2026 כבר מביאים; הסימונים בעורך עובדים גם בלעדיו.
3. התחלה מהירה
רוצים לראות איך זה עובד לפני שאתם מחברים את הפרויקט שלכם? הורידו את פרויקט הדגמה (כ-6 KB — פרויקט C זעיר עם lcov.info מוכן מראש):
- חלצו אותו לכל מקום, ואז פתחו את
coverage-studio-demo.code-workspaceב-VS Code (File → Open Workspace from File…). - התקינו את Fucini Coverage Studio אם עדיין לא עשיתם זאת (ראו §2 למעלה).
- קובץ ה-
.vscode/settings.jsonשל סביבת העבודה כבר מצביע עלcoverage/lcov.infoהמצורף, כך שהפסים ותצוגת Covered Files מופיעים ברגע שהתוסף מופעל — אין צורך בשלבLoad Coverage. - רוצים ליצור מחדש את קובץ המעקב בעצמכם (למשל עם מהדר אחר)? הריצו את
scripts/gen-coverage.sh(או.ps1ב-Windows) — עיינו בקובץ ה-README.mdשל סביבת העבודה לרשימת המהדרים הזמינים.
ב-Visual Studio. פתחו פתרון, או תיקייה (File → Open → Folder, כך פותחים פרויקט CMake) — הדמו שלמעלה נפתח כתיקייה, וה-.vscode/settings.json שלו נקרא גם שם. דוח במקום שההגדרות מציינות נטען מעצמו, וחלונית Fucini Coverage של חלון Output אומרת אילו קבצים; אחרת Tools → Coverage Studio → Load Coverage File…, פעם אחת — זה נזכר. פתחו קובץ מקור ובחרו Show Coverage in Editor: אדום הוא שורה שמעולם לא רצה, ענבר החלטה שהתקבלה רק בכיוון אחד, ו-Ctrl+Shift+U, N עובר לשורה הלא מכוסה הבאה. View → Other Windows → Coverage הוא העץ עם המספרים של כל קובץ וציון אחד על כולם, ששורת המצב מציגה עבור הריצה ועבור הקובץ שבו אתם נמצאים. Tools → Coverage Studio → Getting Started פותח את השלבים האלה כעמוד עם כפתור לכל אחד; בפעם הראשונה הוא נפתח מעצמו.
- הפיקו קובץ מעקב כיסוי עם תהליך הבדיקה הרגיל שלכם.
- Command Palette (
Ctrl+Shift+P) →Fucini Coverage: Load Coverage. עםwatch.enabledמופעל (ברירת המחדל), קובץ מתאים נטען אוטומטית. - פתחו קובץ מקור מכוסה: שורת המצב מציגה את האחוז שלו, תצוגת הכיסוי מתמלאת, ריחוף על שורה מציג את מספר הפגיעות שלה, וההרצה מופיעה בחלונית Test Coverage המובנית. פסים על שורות לא מכוסות, מפת חום של מספרי פגיעות ומוני
×Nבתוך השורה נמצאים במרחק הגדרה אחת (editorGutter.mode,hitCounts.inline).
Screenshot pending — add assets/img/gutters.png (see SCREENSHOTS.md).4. הפקת קובצי מעקב
כל אחד מהבאים מזוהה אוטומטית בעת הטעינה:
מתכונים מלאים להעתקה-הדבקה לכל מהדר — כולל Swift, Rust, Go, Python, .NET, PHP ועוד — בעמוד מתכוני כיסוי: 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 הוא הקלט העשיר ביותר — הוא נושא אזורים, MC/DC ומופעי תבניות 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
| פורמט | קובץ טיפוסי | מדדים נוספים |
|---|---|---|
| LCOV | lcov.info | שורות, הסתעפויות, פונקציות |
| llvm-cov JSON | coverage.json | + אזורים, MC/DC, מימושים |
| Cobertura XML | coverage.xml | שורות, הסתעפויות |
| JaCoCo XML | jacoco.xml | שורות, הסתעפויות, פונקציות |
| Istanbul / nyc | coverage-final.json | פקודות, הסתעפויות, פונקציות |
| SimpleCov | .resultset.json | שורות |
| Clover XML | clover.xml | שורות, הסתעפויות, פונקציות |
| OpenCover XML | coverage.opencover.xml | שורות, הסתעפויות, פונקציות |
| coverage.py JSON | coverage.json | שורות, הסתעפויות |
| gcov / gcovr JSON | coverage.json | שורות, הסתעפויות, פונקציות |
| Go coverage profile | coverage.out | שורות |
| SonarQube generic | coverage.xml | שורות, הסתעפויות |
| GNATcoverage XML (Ada) | *.xml | שורות, הסתעפויות, MC/DC |
| BullseyeCoverage XML | coverage.xml | שורות, תנאי/החלטה |
| Visual Studio | *.coveragexml | שורות, הסתעפויות |
| Coveralls JSON | coveralls.json | שורות, הסתעפויות |
| Xcode xccov JSON | coverage.json | פונקציות וסיכומים לכל קובץ — ללא נתונים לכל שורה |
| gcov plain text | *.gcov | שורות, הסתעפויות, קריאות לפונקציות |
| VectorCAST | coverage.xml | שורות, הסתעפויות, זוגות MC/DC, פונקציות, קריאות לפונקציות |
| Testwell CTC++ | *.txt | שורות, תנאי/החלטה |
| Lauterbach TRACE32 | *.xml | פקודות, החלטות, תנאים, MC/DC, פונקציות, קריאות, קוד אובייקט |
| EMMA XML (Java) | coverage.xml | שורות |
| UCIS / Aldec UCDB | *.xml | פקודות, הסתעפויות החלטה |
| NCover XML | Coverage.xml | שורות, פונקציות |
| dotCover DetailedXML | dotCover.xml | שורות, פונקציות |
| PIT (mutation) | mutations.xml | ציון מוטציה — ללא כיסוי |
| Stryker (mutation) | mutation-report.json | ציון מוטציה — ללא כיסוי |
פרויקט C++ נייטיב, נמדד מתוך Visual Studio
ב-Visual Studio. הכיסוי של Visual Studio עצמו לפרויקט C++ היה זמין רק ב-Enterprise, ותוסף OpenCppCoverage החינמי שמילא את החסר הוצא משימוש. Tools → Coverage Studio → Run Native Project with Coverage לוקח את פרויקט ההפעלה — .vcxproj — שואל את MSBuild לאן הוא נבנה ועל איזה toolset, ומודד אותו באחת משתי דרכים. על ה-toolset של ClangCL, כש-llvm-profdata ו-llvm-cov של LLVM נמצאים במחשב (הרכיב C++ Clang tools for Windows של Visual Studio מביא אותם), הוא בונה את הפרויקט שוב אל coverage\native\ עם -fprofile-instr-generate -fcoverage-mapping, דרך קובץ props ש-MSBuild מתבקש לייבא תחילה — דבר בפרויקט אינו משתנה — מריץ את התוכנית כש-LLVM_PROFILE_FILE מוגדר, ממזג את הפרופיל ומייצא coverage\native\lcov.info, מדויק עד רמת ה-region. על כל toolset אחר, כש-OpenCppCoverage מותקן, הוא בונה את הפרויקט כפי שהוא — ל-build של Debug יש את קובצי ה-PDB — ומריץ אותו תחת OpenCppCoverage, שכותב coverage\native\opencppcoverage.xml. כל פקודה הולכת לחלונית Fucini Coverage, והדוח נטען ונזכר כפי שדוח של הרצת בדיקות נטען. לפרויקט שאינו ניתן למדידה נאמר מדוע ומה להתקין. MSBuild 17.8 (Visual Studio 2022 17.8) ומעלה, בשביל השאלה שהוא שואל.
Screenshot pending — add assets/img/vs-native-run.gif (see SCREENSHOTS.md).5. טעינה וגילוי
כברירת מחדל, התוסף סורק משורש סביבת העבודה. דייקו זאת בשתי הגדרות:
{
"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"
]
}
- כל ערך ב-
pathsהוא יחסי ל-defaultLocation(או לשורש סביבת העבודה כשלא הוגדר). - ערך המכיל
*נחפש רקורסיבית; שם קובץ חשוף תואם רק ישירות בתיקיית הבסיס. - כאשר
pathsריק, התוסף מחפשcoverage.json, ואזlcov.info, וטוען את מה שהוא מוצא ראשון. - Pick Coverage File משתמש בקבצים שבחרת במקום נתיבים אלה — כל בחירה מתווספת לקבוצה וכולם ממוזגים — עד שתבטל את טעינתם או תערוך הגדרות אלה.
- משתנים — כל הגדרת נתיב מרחיבה
${workspaceFolder},${workspaceFolderBasename},${userHome},${env:NAME},${command:id}ו-${config:section.key}. משתנה שההרחבה אינה מכירה נשאר כפי שנכתב, כך ששגיאת הקלדה מופיעה ביומן הגילוי כנתיב שחיפשה במקום להיעלם.${command:id}מריץ קודם את הפקודה — רק בסביבת עבודה מהימנה ולכל היותר חמש שניות — כך ש-${command:cmake.buildDirectory}עוקב אחרי ערכת CMake שנבחרה. - ערכי כתובת — ערך
http(s)://נשלף לאחסון של ההרחבה בכל טעינה ונטען משם; תצוגת הכיסוי מציינת את הכתובת. כל שליפה מותנית (ETag / Last-Modified), כך שארטיפקט שלא השתנה אינו מוריד דבר, וכששליפה נכשלת נטען במקומה העותק האחרון שהורד, עם הסיבה בפלט.remote.headersמוסיף כותרותName: valueעם הרחבת משתנים,remote.refreshMinutesשולף מחדש לפי שעון, ומקטע#lcov.infoמציין את הפורמט כשהכתובת עצמה אינה מסתיימת בשם קובץ. - תבניות התעלמות —
fuciniCoverage.ignoreמשמיט קבצים שלמים (של ספקים, שנוצרו אוטומטית, של צד שלישי) מההרצה בזמן טעינתה, כך שכל תצוגה, שער וייצוא סופרים בלעדיהם; תוצאת הטעינה אומרת כמה הושמטו והפלט מציין אותם בשמם. תבניות תואמות את הנתיב היחסי לסביבת העבודה ואת הנתיב המוחלט, ותבנית ללא/תואמת שם תיקייה או קובץ בכל עומק, כמו.gitignore. - סביבות עבודה מרובות שורשים — כל תיקייה מתגלה בתנאים שלה:
defaultLocation,paths,pathRemap,ignore,watch.*ו-remote.*נקראים לכל תיקייה, כך שה-.vscode/settings.jsonשל התיקייה עצמה או הרשומה שלה ב-.code-workspaceחלים, ו-${workspaceFolder}בערך פירושו התיקייה של אותו ערך. קובצי המעקב של כל התיקיות ממוזגים להרצה אחת, תצוגת הכיסוי מקבצת את הקבצים לפי תיקייה, ותיקייה שנוספה לסביבת העבודה או הוסרה ממנה טוענת מחדש את הכיסוי מעצמה. - טעינה מחדש אחרי משימה —
watch.reloadAfterTasksמציין משימות (labelמ-tasks.json, אוsource: nameכפי שרשימת Run Task מציגה אותן) שסיומן טוען מחדש את הכיסוי, בין אםwatch.enabledמופעל ובין אם לא — לבניות שהצופה אינו יכול לעקוב אחריהן. גם ערך מוחלט ב-pathsמחוץ לסביבת העבודה נדגם, כך שקובץ שמופיע שם נטען. - התקדמות שאפשר לבטל — טעינה של עשרה קובצי מעקב או יותר, או 8 MB או יותר מהם, רצה תחת הודעת התקדמות עם כפתור ביטול שמציינת את הקובץ הנקרא ואת השלב; טעינה קטנה יותר רק מסובבת את שורת המצב. ביטול משאיר את ההרצה הקודמת טעונה ואומר זאת.
מאז 1.2026.6 גם ערך מוחלט יכול להכיל תו כללי: ${workspaceFolder}/build/coverage-merged/*.lcov.info טוען כל קובץ כזה באותה תיקייה, ו-** מייצג כל עומק. התיקיות שלפני התו הכללי הראשון הן המקום שבו הוא מחפש, והן נצפות, כך שדוח שבנייה כותבת שם נטען מעצמו. המהדורה ל-Visual Studio קוראת ערך כזה באותו אופן, ומאז 1.2026.5 גם שם תו כללי יחסי נחפש בכל עומק, כפי שתמיד היה כאן.
כאשר paths אינו מוגדר, נטען הראשון מבין שמות הדוחות המוכרים שנמצא תחת תיקיית הבסיס. תחילה הארבעה שההרחבה חיפשה תמיד — coverage.json, lcov.info, coverage.out, clover.xml — לאחר מכן, מאז 0.2026.83, jacoco.xml, coverage.xml, cobertura.xml, coverage.cobertura.xml, coverage.opencover.xml ו-coverage-final.json, ואז המקומות שאליהם כותבות תצורות ברירת המחדל: coverage/ (nyc, Jest, vitest, PHPUnit, SimpleCov), target/site/jacoco/jacoco.xml (Maven), build/reports/jacoco/test/jacocoTestReport.xml (Gradle) ו-TestResults/*/coverage.cobertura.xml (dotnet test). כך פרויקט Java או .NET מציג את הכיסוי שלו כבר בפתיחה הראשונה, כפי שפרויקט lcov עשה תמיד.
מאז 1.2026.3 פתרון .NET זקוק לעוד פחות: תיקיית TestResults/<run>/ של כל פרויקט בדיקות נמנית עם המקומות המוכרים, לא רק זו של תיקיית סביבת העבודה עצמה, וקובץ <user>_<machine>_<date>.cobertura.xml של המאסף של Microsoft נמצא לצד coverage.cobertura.xml של Coverlet — כך שפתרון שבדיקותיו הורצו ב-Test Explorer של Visual Studio מציג את הכיסוי שלו בפתיחה הראשונה, כל תיקיית הרצה נטענת, והמיזוג משאיר לכל קובץ את המילה האחרונה של ההרצה החדשה ביותר. ו-fuciniCoverage.ignore.generated, שמופעל כברירת מחדל, משאיר קובצי מעצב וקבצים שנוצרו אוטומטית — *.Designer.cs, *.g.cs, *.generated.cs, *.razor.g.cs, AssemblyInfo, using גלובליים, Migrations/ ו-obj/ — מחוץ לכל סיכום, עמוד וייצוא עוד לפני ש-ignore מוחל, כך שטבלה שנוצרה אוטומטית ושאיש אינו בודק אינה עולה לפתרון בסף שלו.
ב-Visual Studio: כיסוי אחרי כל הרצת בדיקות. הריצו את הבדיקות כרגיל. Tools → Coverage Studio → Collect Coverage in Test Explorer… מניח לצד הפתרון קובץ .runsettings אחד עם מאסף ה-Cobertura של Microsoft. Visual Studio קולט אותו כאשר Tools → Options → Test → Auto detect runsettings files מופעל; אחרת בחרו אותו פעם אחת תחת Test → Configure Run Settings. מרגע זה כל הרצה כותבת דוח תחת פרויקט הבדיקות, והמעקב אחר הפתרון טוען אותו ברגע שהוא מופיע, ממוזג עם כל מה שההגדרות מציינות — מ-Test Explorer, ממסוף או מסקריפט באותו אופן. דבר אינו מתחבר ל-Test Explorer, ולכן Visual Studio 2026 ו-Microsoft.Testing.Platform עובדים כפי שהם. Run Tests with Coverage היא פקודת VS Code: היא מזהה dotnet test, vitest, jest, pytest, go, cargo, maven, gradle, phpunit ו-ctest, מריצה את הבדיקות עם כיסוי מופעל בחלון Output וטוענת את מה שכתבו; פרויקט בדיקות ללא coverlet.collector מורץ עם המאסף שמגיע עם ה-SDK של הבדיקות, ו-testRun.skipWhenTestsFail משאיר על המסך את הכיסוי התקין האחרון כשהרצה מסתיימת באדום.
ארטיפקט CI מאחורי אסימון, שנבדק מחדש כל רבע שעה — האסימון נשאר בסביבה, לעולם לא ב-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).טעינה מחדש שקטה בכוונה — תיבת דו-שיח אחרי כל בנייה היא שאלה שיש לה תשובה אחת. מה שאינו שקט הוא סמל Coverage: כל עוד התצוגה אינה מולכם הוא נושא את מספר קובצי המעקב שנקראו שוב, והחיווית שלו מציינת אותם בשם. פתחו את התצוגה והמונה נעלם.
Screenshot pending — add assets/img/coverage-badge.gif (see SCREENSHOTS.md).קבצים שלעולם אינם אמורים להיספר, יהיה אשר יהיה מה שקובץ המעקב אומר עליהם:
{
"fuciniCoverage.ignore": ["vendor/**", "**/*.generated.ts", "build/**"]
}
טעינה מחדש כשמשימת הבדיקות מסתיימת, עבור בנייה שצופה הקבצים אינו יכול לעקוב אחריה — הרצה שמחליפה עץ פלט מקושר סימבולית, דוח על שיתוף רשת, שלב כיסוי שמעבד את הקובץ שלו לאחר מעשה:
{
"fuciniCoverage.watch.reloadAfterTasks": ["npm: test", "coverage-report"]
}
6. מיזוג הרצות
כל רשומת paths קיימת נטענת וממוזגת להרצה אחת. המיזוג דטרמיניסטי — התוצאה אינה תלויה בסדר הטעינה — וקובץ שנמדד על ידי יותר מקובץ מעקב אחד לוקח את מספריו מזה שה-mtime שלו בדיסק הוא החדש ביותר: הרצה חוזרת של מודול מחליפה את מה שהרצה רחבה וישנה יותר אמרה עליו, במקום להתווסף אליה. תצוגת הכיסוי מראה מה זה עשה: כל שורת קובץ מציינת את קובץ המעקב שממנו באו מספריה, התג מוקף במסגרת היכן שמספרים אלה גברו על דוח ישן יותר, כל שורת קובץ מעקב מעל העץ סופרת כמה מקבציה נדרסו או דרסו אחרים, ולחיצה על שורת קובץ מעקב מדגישה את קבציה בעץ עד ללחיצה נוספת (coverageView.mergedMarks מכבה את המסגרת ואת ההדגשה).
ריצה ממוזגת יכולה לשאת יותר מששת המדדים הקלאסיים, כל אחד מהדוח שמודד אותו: קריאות לפונקציות, קוד אובייקט וציון מוטציות לצד שורות, פונקציות, אזורים, הסתעפויות, MC/DC ומימושים. תצוגת Coverage מציגה עמודה לכל מדד שהריצה נושאת — ואף לא אחת למדד שאינה נושאת — מסודרות לפי המשקל של כל מדד בציון שלכם, הכבד ביותר ראשון, בכל רוחב — מה שלא נכנס נגלל הצידה במקום להיעלם. גררו את התצוגה לחלונית התחתונה והיא הופכת לטבלה. כרטיסי שורת המצב, דוח ה-HTML והייצוא ל-CSV ול-Markdown פועלים לפי אותו כלל: מה שהדוח נושא מוצג, ומה שאינו נושא מושמט ואינו מודפס כאפס.
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).מאיזה דוח בא קובץ
כשכמה דוחות טעונים מודדים את אותו קובץ, החדש ביותר זוכה בו לגמרי — וזה נכון כשהרצה חוזרת של מודול מחליפה את מה שאמרה הרצה ישנה ורחבה יותר. זה שגוי כשהדוחות מודדים את אותו קוד בכוונה: אז העורך מדלג ביניהם עם כל בנייה, וכל אחד מספר רק חלק מהסיפור. coverageFile.sources קובע מה לעשות במקום זאת, לכל קובץ. שלושה מצבים מצריכים זאת:
- דוח אחד הוא הטוב יותר. ה-
coverage.jsonשל llvm-cov כולל MC/DC, ו-gcov.infoשל GCC מאותה בנייה רק שורות וענפים: בחרו ב-coverage.json, ושמרו את השני לקבצים המעטים שרק GCC בונה. - כמה חבילות בדיקה של בנייה אחת. בדיקות יחידה, בדיקות אינטגרציה ו-hardware-in-the-loop כותבות כל אחת דוח; כל אחד לבדו משמיט שורות שהאחרים הריצו. שילוב, union: שורה מכוסה היכן שדוח כלשהו הריץ אותה, והספירות מתחברות.
- בסיס קוד אחד, שני מהדרים. אותם מקורות, כשהם נבנים ב-clang וב-GCC, עוברים בנתיבים שונים בקוד הייחודי לכל שרשרת כלים — intrinsic כאן, חלופה ניידת שם — וכל דוח אומר שהחצי השני מעולם לא רץ. שילוב, agree: שורה מכוסה רק היכן שכל דוח שמודד אותה הריץ אותה, והשורות שעליהן הם חלוקים מסומנות בטורקיז. זו השאלה שבדיקה צולבת בין מהדרים שואלת: מה באמת הפעילה כל בנייה שאני משחרר?
לעתים רחוקות תכתבו את הכללים ביד. לחצו לחיצה ימנית על קובץ בתצוגת כיסוי ובחרו Choose Coverage Source... (או הריצו Choose Coverage Source for This File... על הקובץ הפתוח): הרשימה מציגה כל דוח שמודד את הקובץ, כל אחד עם השורות, הענפים וה-MC/DC שלו, ואחריהם Combine them — agree ו-Combine them — union; בחרו אחד וציינו אם הוא חל על הקובץ, על התיקייה שלו או על תבנית. Clear Coverage Source for This File... מסיר את הכלל שוב. בהגדרות, כל כלל הוא glob על הקבצים, glob על הדוח (תבנית בלי / מתאימה לשם הקובץ של הדוח, {a,b} מציין כמה) ולצורך שילוב, "combine": "agree" או "union". מכריע הכלל הראשון שהקבצים שלו תואמים והדוח שלו מודד את הקובץ; קובץ שרק דוח אחד מודד לעולם אינו נלקח ממנו. הענפים, ה-MC/DC והאזורים של קובץ משולב באים מהדוח העשיר בהם ביותר. coverageFile.mergeStrategy: "order" מכריע את הקבצים שאף כלל אינו מתייחס אליהם לפי הסדר ב-coverageFile.paths במקום לפי הזמנים.
{
"fuciniCoverage.coverageFile.paths": ["clang.json", "gcc/bits.gcov.json.gz"],
"fuciniCoverage.coverageFile.sources": [
{ "files": "src/**", "report": "{clang.json,bits.gcov.json.gz}", "combine": "agree" }
]
}
מה רואים: השורה של הקובץ בתצוגת כיסוי מציינת את הדוח שממנו באים המספרים שלו, או, כשהוא משולב, כל דוח ואת המצב, עם ≠ n לשורות השנויות במחלוקת. השוליים וה-Annotated Source מסמנים את השורות האלה בטורקיז ומציינים איזה דוח הריץ אותן וכמה פעמים. כרטיס הריחוף של שורת המצב מציין את המקור של הקובץ הפתוח, ולגבי ההרצה כולה, את הכללים שבתוקף ואת האופן שבו הוכרעו שאר הקבצים. samples/c-cross-check שבהדגמה הוא המקרה של שני מהדרים, מוכן לפתיחה. גם Visual Studio עושה את כל זה: Choose Coverage Source... בשורה בתצוגת כיסוי, ו-Choose ו-Clear Coverage Source for This File... תחת Tools > Coverage Studio.
בחירה ושילוב של מקורות הם חלק מהתוכניות בתשלום. ב-Community הדוח החדש ביותר זוכה בכל קובץ, כמו בלי כלל, וכלל בהגדרות מדווח כלא בשימוש במקום שיתעלמו ממנו בשקט.

bits.c מתוך תצוגת כיסוי — הדוח של clang, הדוח של GCC, או שניהם משולבים.


bits.c, clang ו-GCC משולבים לפי agree — השורה מציגה ≠ 4, וארבע השורות שרק בנייה אחת הריצה צבועות בטורקיז.
bits.c מגיע ל-100% מהשורות שלו — והשורות שהבניות חלוקות עליהן נשארות בטורקיז.


7. מיפוי מחדש של נתיבים
CI לעיתים קרובות מתעד נתיבים מוחלטים של מכונת ה-build שאינם קיימים בתחנת העבודה שלכם. שכתבו אותם עם כללים מסודרים:
{
"fuciniCoverage.pathRemap": [
{ "from": "/builds/ci/project", "to": "${workspaceFolder}" },
{ "from": "\\\\", "to": "/" }
]
}
הכללים חלים לפי סדר; ההתאמה הראשונה מנצחת לכל קידומת. השתמשו בזה כדי לאחד הבדלי מפרידים בין Windows/Unix או למפות נתיב קונטיינר אל ה-checkout שלכם.
לעיתים רחוקות תצטרכו לכתוב את הכלל בעצמכם. ה„נטען אבל שום דבר לא נדלק“ הנפוץ ביותר הוא קובץ מעקב שנתיביו מגיעים מקונטיינר או מ-checkout של CI (/build/src/a.c, /home/runner/work/repo/repo/src/a.c, C:\agent\_work\1\s\src\a.c) בעוד שבסביבת העבודה יש src/a.c. כשטעינה משאירה קבצים ללא התאמה, ההרחבה מחפשת את שמות הקבצים בסביבת העבודה, מסיקה את כלל הקידומת שמסביר את רובם, רושמת אותו כ-[FUCINI_REMAP_002], ותוצאת הטעינה מציעה Apply Suggested Remap — לחיצה אחת מוסיפה את הכלל ל-fuciniCoverage.pathRemap וטוענת מחדש. Suggest Path Remap Rule מריץ את אותו ניתוח לפי דרישה מלוח הפקודות. שום דבר אינו נכתב בלי הלחיצה.
to יכול להשתמש ב-${workspaceRoot}, שמייצג את תיקיית סביבת העבודה שבה נמצא קובץ המעקב; בסביבת עבודה מרובת שורשים הוא מנסה תחילה את התיקייה הזו, ואז כל תיקייה אחרת שמתברר שהקובץ נמצא בה. הכללים עצמם נקראים לכל תיקייה, כך שכל שורש בסביבת עבודה מרובת שורשים יכול לשאת כללים משלו.
8. כיסוי בתוך העורך
- שוליים וסרגל — כברירת מחדל השוליים של העורך עצמו מציגים רק ממצאים: פסי MC/DC, משולשי „מאז ההרצה האחרונה“, נקודות של שורות שנערכו.
editorGutter.modeמוסיף פסים על שורות לא מכוסות בלבד או מפת חום של מספרי פגיעות (להלן); התצוגה הצבעונית של קובץ שלם היא ה-Annotated Source. - CodeLens לפונקציות — אחוז כיסוי מעל כל פונקציה; לחצו כדי לקפוץ לשורה הלא-מכוסה הראשונה שלה. הפעילו/כבו עם
codeLens.enabled. - מעבר עכבר על ענפים ו-MC/DC — העבירו עכבר על שורת החלטה לספירות נלקחו/לא נלקחו לכל ענף וטבלת וקטור לכל תנאי. הפעילו סרגל שוליים צבעוני עם
mcdcGutter.enabled. - אזהרות קוד מת — פונקציות עם שורות מדידות וכיסוי אפס מסומנות בפאנל Problems (
deadCode.enabled). - Next / Previous Uncovered — קפצו בין פערים.
- שורת מצב — פריט
$(dashboard) NN%ברמת ההרצה ופריט לכל קובץ, שניהם צבועים לפי הציון המורכב; העבירו עכבר לטבלת מדדים מלאה. - תגי הסייר — תגי כיסוי לכל קובץ ולכל תיקייה, עם פירוט לפי מדד בריחוף. כבויים כברירת מחדל: הפעילו אותם עם
explorerBadges.enabled. - מאז ההרצה האחרונה — משולש אדום על כל שורה שבוצעה בהרצה הקודמת ולא בזו, ירוק למקרה ההפוך, עם סרגל הסקירה ומספרי הפגיעות בריחוף.
- מאגרים שנערכו — כל סימון, ריחוף ו-CodeLens זזים עם הטקסט בזמן העריכה ונסוגים משורה שנכתבה מחדש, שם נקודה אפורה אומרת מדוע.
- מספרי פגיעות בתוך השורה —
hitCounts.inlineכותב×12אחרי כל שורה שפקודה מתחילה בה, כולל×0: המספר שתמיד היה בריחוף, בלי לרחף. Toggle Inline Hit Counts מחליף את המצב; תפריט שורת המצב מציע אותו כ„הצג“ או „הסתר“, לפי העניין. - רשומות Problems לכל שורה —
problems.perLineמציב אבחון מסוג Information, עם קו גלי בעורך, על כל בלוק רציף של שורות שמעולם לא רצו במסמך פתוח (פונקציה מתה בת ארבעים שורות היא רשומה אחת, לא ארבעים) וכ-uncoveredAndPartialגם על כל שורה שענף שלה מעולם לא נלקח. הרשומות עוקבות אחרי השורות שלהן בזמן העריכה ונעלמות כשהמסמך נסגר; הרשומה לכל קובץ שמאחוריproblems.enabledלא השתנתה. - צביעת שורה —
lineHighlightמניח גוון שקוף למחצה מאחורי השורות עצמן, עבור מה שהשוליים מסמנים (uncovered, אוheatmapגם עבור השורות שרצו). הגדרה עצמאית, כדי שהשוליים יוכלו להישאר נקיים בזמן שהפערים נצבעים, או להפך. - סרגל הסקירה —
overviewRulerמחליט על הפס בפס הגלילה בנפרד מהשוליים: follow(יחד עם הפסים, כמו קודם), uncovered(תמיד, כך שהשוליים יכולים להיות כבויים בזמן שפס הגלילה עדיין ממפה את הפערים) אוoff. - איזה קובץ מעקב כיסה שורה — כששולבו כמה דוחות, החלונית עם מספר הריצות מסתיימת ב-מכוסה על ידי: ובכל דוח שכיסה את השורה, כולל שם החבילה מתוך
TN:של lcov; לחיצה על שורת קובץ מעקב בתצוגת Coverage מדגישה את השורות שהוא תרם בכל עורך פתוח.
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).מצבי השוליים של העורך
editorGutter.mode קובע מה השוליים של העורך עצמו מציגים על הכיסוי, מעבר לממצאים שהם תמיד מציגים. off (ברירת המחדל) הוא רק אלה. uncovered מציב פס על כל שורה שמעולם לא רצה ופס ענברי על כל שורה שענף שלה מעולם לא נלקח, ושום דבר על שורות מכוסות, כך שקיר ירוק אינו מסתיר את שלוש האדומות. coverage מוסיף פס ירוק על כל שורה מכוסה, כך שהקובץ כולו נקרא באדום, ענבר וירוק בצבעי סולם הצבעים. heatmap מוסיף במקום זאת גוון חם על כל שורה שבוצעה, חם יותר ככל שרצה יותר פעמים — הוא מראה כמה פעמים שורה רצה, לא אם היא מכוסה, ולכן קובץ ב-100% נראה שם בין צהוב לחום, אף פעם לא ירוק. Choose Editor Gutter Mode... בוחר אחד מלוח הפקודות או מתפריט שורת המצב; לחצן המצב בצד ימין של שורת המצב, או Alt+G, עובר למצב הבא בלחיצה אחת (statusBar.showModeToggle מסתיר את הלחצן). שניהם כותבים את ההגדרה. הדוגמה מפעילה יחד את הפסים על שורות לא מכוסות ואת המונים בתוך השורה:
{
"fuciniCoverage.editorGutter.mode": "uncovered",
"fuciniCoverage.hitCounts.inline": true
}
Screenshot pending — add assets/img/gutters.png (see SCREENSHOTS.md).
coverage — ירוק היכן ששורה רצה במלואה, ענבר היכן שענף מעולם לא נלקח, אדום היכן שדבר לא רץ. פריט שורת המצב של הקובץ מציין את הדוח שממנו באים המספרים שלו; לחצן המצב לצדו אומר Coverage.
Alt+G ארבע פעמים — heatmap, off, uncovered, ובחזרה ל-coverage.
Quote.cs.מפת החום יחסית לקובץ. הגוון של שורה משווה את המונה שלה לשורה החמה ביותר באותו קובץ, בסולם לוגריתמי ובחמש דרגות — כך שגוף לולאה שרץ אלף פעמים ופונקציה שרצה פעמיים נראים שניהם, בלי שהאחד יבלע את האחר, וקובץ שבו הכול רץ פעם אחת בדיוק נראה חם באופן אחיד ולא חיוור באופן אחיד. בערכת נושא כהה הסולם נע מירוק-זית עמום לכתום עז, ובערכת נושא בהירה מצהוב חיוור לחום: בשני המקרים יותר צבע פירושו יותר הרצות, והאדום נשאר שמור לשורות שלא רצו מעולם. lineHighlight: "heatmap" מניח את אותם גוונים מאחורי הקוד כרקע צבעוני, ו-hitCounts.inline כותב את המספר המדויק אחרי השורה.
{
"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).הצבעים שלכם. colorScale.lowColor, midColor ו-highColor קובעים את האדום, הענבר והירוק של השוליים, של צביעת השורות ושל כל אחוז; heatmap.colors ו-heatmap.colorsDark מחזיקים את חמשת הגוונים של מפת החום לערכת נושא בהירה ולכהה, מהשורה שרצה הכי מעט לשורה שרצה הכי הרבה. דף ההגדרות מציג את התוצאה לפני שמשהו נשמר: תחת Colour scale תצוגה מקדימה נשארת בעין בזמן שהשורות גוללות — המדרג עם שתי נקודות הציר שלו, כמה אחוזים בצבעיהם, ועורך בהיר קטן ועורך כהה קטן שצבועים במצב coverage ובמפת החום — והיא נצבעת מחדש ברגע שנבחר צבע.
{
"fuciniCoverage.heatmap.colors": ["#e3f2fd", "#90caf9", "#42a5f5", "#1e88e5", "#0d47a1"]
}


החלק בשורה שמעולם לא רץ
שורה מכוסה או שאינה מכוסה, והאמת נמצאת לעיתים קרובות באמצע: return x > hi ? hi : x; רצה, אך הזרוע hi שלה מעולם לא רצה. כאשר lineHighlight פעיל, החלק שמעולם לא בוצע בשורה שבוצעה נצבע בעורך, בכל פורמט שנושא טווחי עמודות (llvm-cov, Istanbul, Go, dotnet-coverage) — אותם טווחים ש-Annotated Source מסמן. רק בשורות שרצו: שורה שמעולם לא רצה כבר מסומנת בשלמותה. תבנית C++ נחשבת כמבוצעת במקום שבו מופע כלשהו שלה ביצע אותה; מה שעשה כל מופע הוא מה שמדד המופעים מדווח.
Screenshot pending — add assets/img/partial-line.png (see SCREENSHOTS.md).אילו בדיקות הריצו את השורה הזו
חלק מהדוחות אומרים לא רק ששורה רצה אלא גם אילו בדיקות הריצו אותה: coverage.py שנכתב באמצעות coverage json --show-contexts עם dynamic_context = test_function בקובץ .coveragerc, OpenCover שנאסף עם -coverbytest, ו-tracefile של lcov שנכתב מקטע אחד לכל בדיקה (TN:), שמקטעיו מסוכמים לרשומה אחת עם בדיקות לכל שורה. רחפו מעל תחילת השורה, במקום שבו נמצא מספר הפגיעות, והבדיקות יוצגו בשמן — מקוצרות למחלקה ולמתודה, חמש הראשונות בשמן והיתר כמספר; ה-CodeLens של הפונקציה אומר כמה בדיקות הריצו אותה. Show Tests That Ran This Line — מ-Command Palette, מתפריט ההקשר של העורך, ב-Visual Studio מ-Tools → Coverage Studio או Ctrl+Shift+U, T — מונה אותן, העמוסה ביותר תחילה, ופותח את זו שבחרתם במקום שבו היא כתובה בסביבת העבודה. הרצת dotnet test אינה יכולה לומר איזו בדיקה הריצה מה; הגדירו testRun.perTest ו-Run Tests with Coverage מונה את מחלקות הבדיקות ומריץ אותן אחת אחת, כל דוח מתויג במחלקה שלו, כך שהריחוף, ה-lens והפקודה יכולים לענות גם ל-.NET. המידע נשמר לכל קובץ בנפרד, ולכן הוא שורד מיזוג עם דוח שאינו יודע דבר על בדיקות.
{
"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 — הבדיקה שהריצה אותה, ו-Go to Test שפותח אותה.הצלחה או כישלון בסימונים
שורה מכוסה נראית אותו דבר בין שהבדיקה שלה עברה ובין שלא. היכן שהדוח אומר אילו בדיקות הריצו שורה וגם קובץ התוצאות של מריץ הבדיקות אומר איך הן הסתיימו, שורה שבדיקה שנכשלה הריצה אותה מקבלת פס אדום בתחילתה ופס בסרגל הסקירה; הריחוף שלה מציין את שמות הבדיקות שנכשלו, ו-Show Tests That Ran This Line כותב נכשלה לצד כל אחת מהן. כשבדיקה אדומה, המקום להסתכל בו הוא הקוד שהיא עברה דרכו. התוצאות נקראות בכל טעינה מהתיקייה של כל דוח — כל קובץ .trx, והשמות שהכלים הכותבים בפורמט JUnit משתמשים בהם (TEST-*.xml, junit*.xml, test-results*.xml) — ומתוך testResults.paths, כנתיבים או כתבניות glob יחסית לתיקייה. Run Tests with Coverage מבקש מ-dotnet test לכתוב test-results.trx לצד הדוח, כך שכאשר testRun.perTest מופעל אין צורך להגדיר דבר. testResults.enabled מכבה את הקריאה הזו.
{
"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).הבדיקות ששינוי נוגע בהן
הרצה מלאה עונה לאט על מה ש-Run Tests Affected by My Changes… עונה מיד: מבין כל הבדיקות, אילו עברו דרך הקוד שערכתי זה עתה? git מתבקש לתת את ה-diff של עץ העבודה מול testImpact.baseRef — HEAD כברירת מחדל, כלומר מה שעדיין לא נכנס ל-commit; origin/main לכל מה שהענף משנה — והבדיקות שהריצו שורה ששונתה מופיעות ברשימה, וראשונה הבדיקה שהריצה את החלק הגדול ביותר של השינוי. בחירה בבדיקה פותחת אותה. היכן שהדוחות הגיעו מהרצה לפי בדיקה (testRun.perTest), הרשומה הראשונה מריצה רק את הבדיקות האלה, כל מחלקה לדוח משלה, כך שהדוחות של כל שאר המחלקות נשארים בעינם והסיכומים נשארים אלה של חבילת הבדיקות כולה. גם בדיקה שהריצה רק שורות מתחת להוספה או להסרה מופיעה ברשימה: אחרת הדוח שלה היה מצביע על השורות הלא נכונות.
Screenshot pending — add assets/img/test-impact.gif (see SCREENSHOTS.md).
Screenshot pending — add assets/img/vs-test-impact.gif (see SCREENSHOTS.md).קבוצת הבדיקות הקטנה ביותר שעדיין מריצה כל שורה
Show Minimal Test Set… עונה על שתי שאלות מתוך אותם נתוני שורות לפי בדיקה: אילו בדיקות מעטות עדיין יריצו כל שורה שחבילת הבדיקות מריצה — להרצה המהירה שלפני commit — ואילו בדיקות אינן מריצות אף שורה שבדיקה אחרת אינה מריצה כבר. הבדיקות שנבחרו מופיעות ראשונות, כל אחת עם השורות שהיא מוסיפה ועם השורות שרק היא מריצה; אחריהן השאר, כל אחת מסומנת כמי שאינה מוסיפה דבר. הבחירה היא הבחירה החמדנית — הבדיקה שמריצה הכי הרבה שורות, ואחריה זו שמוסיפה לה הכי הרבה — ולכן היא קרובה לקבוצה הקטנה ביותר וזהה בכל פעם. מיותרת מבחינת שורות אינה מיותרת מבחינת מה שבדיקה בודקת: בדיקה שאינה מוסיפה אף שורה עדיין עשויה להיות היחידה שמאמתת ערך בשורות האלה. הרשימה אומרת היכן להסתכל כשמצמצמים חבילת בדיקות, לעולם לא מה למחוק.
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).הרצת הבדיקה הזו, עם כיסוי
הציבו את הסמן בבדיקה והריצו Run This Test with Coverage — מ-Command Palette, מתפריט ההקשר של העורך, ב-Visual Studio מ-Tools → Coverage Studio או Ctrl+Shift+U, R — והבדיקה הזו לבדה רצה עם כיסוי מופעל: מתודת הבדיקה שהסמן בתוכה, או מחלקת הבדיקות או בלוק ה-describe כשהוא בין מתודות, או הקובץ כשהוא מעל כל המחלקות. מה שמתחת לסמן נקרא מתוך הטקסט, ולכן זה עובד ל-C#, VB ו-F# ([Fact], [Test], [TestMethod] ודומיהם), ל-JavaScript ו-TypeScript (it, test, describe) ול-Python (def test_…) יהיה שירות השפה המותקן אשר יהיה. מתכון התיקייה מצומצם אליה — dotnet test --filter "FullyQualifiedName~…", jest או vitest <file> -t "…", מזהה node של pytest — ומה שהוא כתב נטען כמו כל הרצה; מריץ שאי אפשר לצמצם אומר זאת, ו-Run Tests with Coverage מריץ את כולן.
Screenshot pending — add assets/img/run-this-test.gif (see SCREENSHOTS.md).
[Fact] — ההרצה ברשימת Tracefiles, והשורות מעל המתודות אומרות שבדיקה אחת הריצה את הקוד.Go ו-Rust. בקובץ Go, func TestXxx (או Fuzz…, Example…) שבה נמצא הסמן רצה לבדה, בחבילה שלה ובשמה המדויק — go test ./pkg/calc -run "^TestTotal$" — וכשהסמן מחוץ לבדיקה, רצה החבילה של הקובץ. בקובץ Rust, פונקציית ה-#[test] רצה לפי הנתיב שלה ב-crate ועם --exact; כשהסמן נמצא בתוך mod ואינו בתוך אף בדיקה, רצות הבדיקות של המודול הזה; בדיקת אינטגרציה תחת tests/ רצה בקובץ בינארי משלה (--test api). מריץ בדיקות מקבל רק קבצים בשפה שלו: קובץ TypeScript בתיקיית Go מקבל משפט הסבר, לא הרצה של שום דבר.
כיסוי אחרי כל שמירה
כש-testRun.onSave מופעל, שמירת קובץ מקור מריצה את הבדיקות המכסות אותו, עם כיסוי, רגע אחרי השמירה, והשוליים מתעדכנים בהתאם. לפתרון .NET הפרויקט של הקובץ שנשמר נמצא דרך גרף ה-.csproj, ורק פרויקטי הבדיקות המפנים אליו — ישירות, או דרך פרויקטים אחרים — מורצים, dotnet test <project> אחד לכל אחד; כל מריץ אחר מריץ את המתכון כולו; קובץ ששום פרויקט אינו הבעלים שלו ושום דוח אינו מודד אינו מריץ דבר. כמה שמירות ברצף הן הרצה אחת, והרצה שכבר בעיצומה אינה נקטעת. השאר כפי ש-Run Tests with Coverage עושה זאת: הטרמינל, חלונית Output, הדוח נטען. כבוי כברירת מחדל — זהו הרגל שבוחרים, לא ברירת מחדל שמגלים.
{
"fuciniCoverage.testRun.onSave": true
}
Screenshot pending — add assets/img/coverage-on-save.gif (see SCREENSHOTS.md).
testRun.onSave מופעל — Quote.cs נשמר, הבדיקות רצות מעצמן, השורה מעל המתודה משתנה.האפליקציה עצמה, עם כיסוי
הרצת בדיקות אומרת איזה קוד הבדיקות מפעילות. גם הקוד שאדם מפעיל — כשהוא עובר בלחיצות על המסכים לפני שחרור גרסה, או משחזר את הצעדים של לקוח — הוא כיסוי, ו-Run App with Coverage… אוסף אותו. אפליקציית ה-.NET של התיקייה — Exe, WinExe, פרויקט web או worker, לעולם לא פרויקט בדיקות; כשיש כמה, בוחרים מרשימה — מופעלת תחת dotnet-coverage של Microsoft בחלון קונסולה משלה, כדי שאפשר יהיה להקליד באפליקציית קונסולה, ורצה עד שתסגרו אותה. מה שעברתם בו נטען אחר כך כמו כל הרצה, ובסשן כיסוי הוא מתווסף למה שהבדיקות הריצו. הדרך שבה האפליקציה הסתיימה אינה נזקפת לחובת ההרצה. את הכלי צריך להתקין פעם אחת: 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).מוטנטים, והיכן הם נמצאים
כלי מוטציות — PIT עבור Java, Stryker עבור JavaScript, C# ו-Scala, Mull עבור C ו-C++ — משנה את הקוד שלכם בדרכים קטנות ומריץ את הבדיקות מול כל שינוי. שינוי שאף בדיקה אינה מבחינה בו הוא מוטנט ששרד: הקוד רץ, ושום דבר לא בדק מה הוא עשה. ציון המוטציות אומר כמה נתפסו; מאז 0.2026.83 העורך אומר היכן נמצאים האחרים. שורה שיש בה מוטנט כזה נושאת הערה אחריה (⚑ 2 mutants survived), הטקסט ששונה מסומן בקו תחתון כאשר הדוח מציין איזה טקסט זה היה (Stryker ו-Mull מציינים), בסרגל הסקירה מופיע פס, ובריחוף מוצג מה שונה, כמה בדיקות הריצו את הקוד, ולגבי המוטנטים שנתפסו — איזו בדיקה תפסה אותם.
Screenshot pending — add assets/img/mutant-hover.png (see SCREENSHOTS.md).שרד פירושו שבדיקות הריצו את הקוד ששונה וכולן עברו. לא נבדק (בדוח: no coverage) פירושו שאף בדיקה אינה מריצה את הקוד הזה כלל, ולכן שום דבר לא יכול היה להבחין בשינוי. מוטנטים שנתפסו נספרים בריחוף ולעולם אינם מסומנים, ומוטנטים שמעולם לא היו מבחן הוגן — למשל כזה שלא היה מתקמפל — נמצאים מחוץ לציון. ב-Annotated Source יש שורה מתחת לכל שורה כזו וכפתור Next Mutant (U), ובדוחות ה-HTML יש מקטע Surviving Mutants שמקשר אל השורה. אין צורך להפעיל דבר, ופרויקט ללא דוח מוטציות אינו רואה מכל זה דבר.
Screenshot pending — add assets/img/mutants.gif (see SCREENSHOTS.md).האם בדיקה הייתה מבחינה? הרצת מוטציות במקום שבו נמצא הסמן
הרצת מוטציות של פרויקט נמשכת שעה; של פונקציה אחת — דקה. Run Mutation Tests Here מבצע את ההרצה בת הדקה הזו: מריץ המוטציות של התיקייה מקבל הוראה להחיל מוטציות על הפונקציה שהסמן נמצא בה — או על השורות שנבחרו, או על הקובץ — והדוח שלו נטען לצד הכיסוי שעל המסך, ושם מסומנים המוטנטים ששרדו. ל-C# זהו Stryker.NET (dotnet tool install --global dotnet-stryker), שמקבל את טווח התווים ואת פרויקט הבדיקות שמפנה אל הפרויקט של הקובץ; ל-JavaScript ול-TypeScript זהו StrykerJS, שמקבל את השורות; ל-Java זהו PIT עם Maven, שמקבל את המחלקה. הדרך שבה מריץ המוטציות הסתיים אינה נזקפת לחובת ההרצה: ציון שמתחת לסף שלו הוא קוד יציאה, ועדיין יש דוח. על מריץ מוטציות שלא כתב דבר נמסרת הודעה, יחד עם מה שצריך להיות מותקן בשבילו.
Screenshot pending — add assets/img/mutation-here.gif (see SCREENSHOTS.md).
Screenshot pending — add assets/img/vs-mutation-here.gif (see SCREENSHOTS.md).תצוגת Test Coverage של VS Code עצמו
עם testCoverage.publish מופעל (ברירת המחדל), כל הרצה טעונה עוברת גם לתצוגת Test Coverage המובנית של העורך — חלונית הכיסוי של Test Explorer, האחוזים לכל קובץ שהיא מציבה ב-Explorer, והמתג Show Inline Coverage של העורך עצמו — כשורות, ענפים ופונקציות, כשהפרטים נטענים לפי דרישה, מכל קובץ מעקב שהגיעו ממנו ובלי שום מתאם בדיקות מעורב. Show in Test Coverage View מפרסם את ההרצה הפעילה ופותח את החלונית יהיה אשר יהיה ערך ההגדרה; תפריט שורת המצב מציע זאת מאחורי quickActions.showTestCoverage. כשההגדרה כבויה, שום רשומת Fucini Coverage אינה מופיעה ב-Test Explorer כלל. כשקובץ מעקב נותן שמות לבדיקות שלו (מקטעי TN: של lcov), כל בדיקה מופיעה תחת Fucini Coverage ב-Test Explorer, והתצוגה יכולה לסנן את הכיסוי של קובץ לפי בדיקה.
Screenshot pending — add assets/img/test-coverage-view.png (see SCREENSHOTS.md).שורות לא מכוסות בחלונית Problems
כבוי כברירת מחדל מפני שהוא רועש מטבעו, ותמיד רק למסמכים הפתוחים — הרצה של אלפיים קבצים אינה יכולה להציף את החלונית. בלתי תלוי ב-problems.enabled, שנשאר ברשומה אחת לכל קובץ:
{
"fuciniCoverage.problems.perLine": "uncoveredAndPartial"
}
Screenshot pending — add assets/img/problems-panel.png (see SCREENSHOTS.md).9. כיסוי הפרשי
הגבילו את הקישוטים לשורות שהשתנו ביחס לענף בסיס ב-git — מושלם לבדיקה מדויקת של מה ש-PR כיסה או לא כיסה:
{
"fuciniCoverage.gitDiff.enabled": true,
"fuciniCoverage.gitDiff.baseRef": "origin/main"
}
Screenshot pending — add assets/img/diff-coverage.png (see SCREENSHOTS.md).ב-Visual Studio. אותן שתי הגדרות, הנקראות מאותם קבצים: ההרחבה מריצה בעצמה git diff <baseRef> לכל קובץ בהרצה ומצמצמת את ההרצה לשורות שהענף שלכם שינה — בשוליים, בחלון Coverage ובספים. חלונית Output אומרת מה git ענה כשהוא אינו עונה דבר.
סף לקוד חדש
threshold.newCode הוא סף בפני עצמו, לצד הספים על ההרצה כולה: מתוך השורות ששונו מול gitDiff.baseRef ושאפשר למדוד אותן, האחוז המינימלי שחייב לרוץ. פרויקט שעומד על 62% בסך הכול עדיין יכול לדרוש שלמה שנכתב היום יהיו בדיקות. הסף מחושב בכל טעינה על ההרצה כולה, שנשארת על המסך — gitDiff.enabled הוא הדבר האחר: השורות ששונו במקום ההרצה. Check Coverage Thresholds ורשומות התאימות ב-Problems מדווחים על הכישלון שלו במשפט משלו: New code 72.00% < 80% (18 of 25 line(s) changed against origin/main ran). שינוי שאין בו אף שורה שאפשר למדוד — הערות, קובץ README — אינו מכשיל דבר.
{
"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).קוד חדש לפי תגית, לפי מחבר, לפי תאריך
קוד חדש הוא כברירת מחדל השורות שעץ העבודה משנה מול gitDiff.baseRef — ענף, commit או תגית: "v1.4.0" הוא כל מה שהשתנה מאז אותה גרסה. שתי הגדרות שואלות את מה ש-ref אינו יכול לשאול. gitDiff.author מקבלת חלק משמו של מחבר, ואז קוד חדש הוא השורות ש-git מייחס לאותו מחבר; gitDiff.since מקבלת יום, ואז קוד חדש הוא השורות ששונו לאחרונה באותו יום או אחריו, יהיה הענף שדרכו הגיעו אשר יהיה; שתיהן יחד — השורות של אותו מחבר מאז אותו יום. השורות האלה נלקחות מתוך git blame, קובץ אחר קובץ — הרצה גדולה תרגיש זאת בכל טעינה — ותופסות את מקומו של ה-diff לצורך כיסוי ה-diff ולצורך הסף שלמעלה. שורה שעדיין לא נכנסה ל-commit נספרת בכל מקרה.
{
"fuciniCoverage.gitDiff.author": "Ada",
"fuciniCoverage.gitDiff.since": "2026-09-01"
}
Screenshot pending — add assets/img/new-code-author.png (see SCREENSHOTS.md).שינויים עקיפים: מה שזז אף שאיש לא נגע בו
ה-diff אומר אילו שורות השתנו; שתי הרצות אומרות אילו שורות הפסיקו לרוץ או התחילו לרוץ. השורות ששווה להסתכל עליהן הן אלה שבהן השניים אינם תואמים: קוד שאיש לא ערך ושכבר אינו רץ, כי בדיקה נמחקה, כי ענף מוקדם יותר במהלך הביצוע חוזר עכשיו מוקדם, כי fixture השתנה. מי שסוקר את ה-diff אינו יכול לראות אותן — מעצם הגדרתן הן מחוצה לו. Show Indirect Coverage Changes… מציג אותן ברשימה לפי קובץ, כשהקובץ שהפסיד הכי הרבה ראשון, ופותח את הקובץ שבחרתם בשורה הראשונה מסוג זה שבו. ההרצה מושווית לקו הבסיס של ה-CI כאשר baseline.report מציין קו כזה — ולפיו נשפט pull request — ואחרת להרצה שקדמה לה; השורות שעץ העבודה משנה מול gitDiff.baseRef, וכל מה שנמצא מתחת למקום שבו השינוי הזה מזיז את שורות הקובץ, נשארים בחוץ.
Screenshot pending — add assets/img/indirect-changes.png (see SCREENSHOTS.md).
Screenshot pending — add assets/img/vs-indirect-changes.png (see SCREENSHOTS.md).10. הציון המורכב
במקום לדווח שישה מספרים, התוסף מקפל אותם לממוצע הרמוני משוקלל (WHM) יחיד. עבור מדדים עם אחוזים pᵢ ומשקלים wᵢ:
WHM = ( Σ wᵢ ) / ( Σ wᵢ / pᵢ )
ממוצע הרמוני נשלט על ידי האיבר הקטן ביותר שלו, כך שמדד חלש לא יכול להיות מוסתר על ידי מדד מושלם — בדיוק התכונה הרצויה משער בטיחות. משקלים ברירת מחדל:
| מדד | משקל | נימוק |
|---|---|---|
| MC/DC | 4 | IEC 61508 SIL 3–4 / ISO 26262 ASIL C–D / DO-178C DAL A–B. |
| הסתעפויות | 2 | IEC 61508 SIL 2+ / ISO 26262 ASIL B+. |
| תנאים | 3 | בין הסתעפויות ל-MC/DC (DO-178C, ISO 26262). |
| אזורים | 1.5 | מסלולים בתוך פקודה (למשל קיצור־דרך חלקי). |
| שורות | 1 | IEC 61508 SIL 1+ / ISO 26262 ASIL A+. |
| פונקציות | 1 | בדיקת קוד מת. |
| מימושים | 0.5 | כיסוי תבניות C++; ההיקף הצר ביותר. |
| קריאות לפונקציות | 1 | אתרי קריאה שבוצעו (gcov, VectorCAST, Testwell CTC++, TRACE32). |
| קוד אובייקט | 0 | כבוי כל עוד לא נתתם לו משקל: הוא כולל בתוכו את כיסוי ההצהרות. |
| ציון מוטציות | 0 | כבוי כל עוד לא נתתם לו משקל: זה אינו כיסוי. |
הגדירו כל משקל ל-0 כדי להסיר את המדד הזה מהציון. מדדים שאינם קיימים בנתונים (למשל MC/DC בהרצת lcov פשוטה) פשוט מושמטים.
המשקל של קוד האובייקט ושל ציון המוטציות הוא 0 עד שתחליטו אחרת (whmWeights.objectCode, whmWeights.mutation). כיסוי קוד אובייקט כולל בתוכו את כיסוי ההצהרות, ולכן מתן משקל לשניהם סופר את אותה ראיה פעמיים; ציון מוטציות אינו כיסוי כלל — חבילת בדיקות יכולה להריץ כל שורה ולא לגלות דבר. לשניהם עדיין יש עמודה משלהם וסף משלהם.
כיסוי תנאים
a && b הוא החלטה אחת — שתי הסתעפויות — ושני תנאים עם ארבע תוצאות. חבילת בדיקות יכולה לעבור בשתי ההסתעפויות ולעולם לא לראות את b כשהוא שקרי: כיסוי ההסתעפויות מלא, וכיסוי התנאים הוא שלוש מתוך ארבע. רמה זו נמצאת בין כיסוי הסתעפויות ל-MC/DC ב-DO-178C וב-ISO 26262, ומאז 0.2026.83 היא מדד בפני עצמו במקום להיבלע בהסתעפויות: שורה בכרטיסי שורת המצב, עמודה בתצוגת Coverage, בדוחות ובייצואים, משקל 3 בציון (whmWeights.conditions) ושער (threshold.conditions; ללא שער בפרופיל standard, 100 בפרופיל safety).
נקרא מגששי condition של BullseyeCoverage, מייצוא cond של TRACE32 ומ-GCC 14 שנבנה עם -fcondition-coverage. בדוח שאינו מבחין בין תנאים להחלטות אין שורה, עמודה או משקל כאלה. אם אתם משתמשים ב-Bullseye או ב-TRACE32: תנאים נספרו עד כה כהסתעפויות, ולכן אחוז ההסתעפויות שלכם משתנה בגרסה זו, ועם המשקל החדש גם הציון המורכב שלכם; הגדירו את whmWeights.conditions ל-0 כדי לקבל את הציון כפי שהיה.
GCC 14, שורה אחר שורה. -fcondition-coverage גורם ל-gcov לומר איזו תוצאה של איזה תנאי חסרה — תנאי 1 מעולם לא היה אמת, תנאי 0 מעולם לא היה אמת ולא שקר — וכל תנאי מסומן בשורה שלו ומצוין בשמו בריחוף, מתוך ה-JSON של gcov ומתוך פלט הטקסט שלו (condition outcomes covered 3/6). המדד נמצא בכל מקום שבו נמצאים האחרים: threshold.conditions קובע לו סף, והסף נשאר בלי הכרעה כשבהרצה אין נתון כזה, ל-Copy Coverage Summary יש עמודת Conditions, badge.metric מקבל conditions, ותיבת החיפוש מקבלת conditions < 80. נתון הענפים של פונקציה אינו כולל את תוצאות התנאים שלה, כמו נתון הענפים של הקובץ ושל ההרצה.
Screenshot pending — add assets/img/gcc-conditions.png (see SCREENSHOTS.md).מורכבות ו-CRAP
חלק מהדוחות נושאים את המורכבות הציקלומטית של כל פונקציה: OpenCover (וזה מה ש-Coverlet כותב), JaCoCo, Clover ו-Cobertura. כשהם עושים זאת, ההרחבה מחשבת לפונקציה ציון CRAP — Change Risk Anti-Patterns — מתוך אותה מורכבות ומתוך הכיסוי שהיא מדדה בעצמה:
CRAP = complexity² × (1 − coverage)³ + complexity
פונקציה פשוטה שנבדקה במלואה מקבלת ציון השווה למורכבות שלה ולא יותר; פונקציה מורכבת שכמעט לא נבדקה מקבלת ציון של מאות. בדוגמת ה-C# של פרויקט ההדגמה ל-Price() יש מורכבות 22 וכ-37% משורותיה מכוסות, מה שנותן 142.2, ואילו ל-Shipping() יש מורכבות 12 והיא מכוסה במלואה, מה שנותן 12. הקו המקובל הוא 30: פונקציה שנמצאת בו או מעליו מופיעה תחת Riskiest Methods בדוח ה-HTML, הגרועה ביותר תחילה.
המורכבות והציון מופיעים ב-CodeLens של הפונקציה ולצד הפונקציה בקוד המקור המוער. Max CRAP הוא הציון הגבוה ביותר מבין הפונקציות בקובץ — הגרוע ביותר, לא ממוצע — והוא עמודה בתצוגת Coverage, בדוח ה-HTML ובייצוא ל-CSV ול-Markdown. זהו מידע בלבד: אין לו סף ואין לו משקל בציון המורכב. לדוחות שאינם נושאים מורכבות (lcov, gcov, Istanbul, coverage.py) אין CRAP, וגם לא עמודה ריקה.
מאז 0.2026.83 הוא קיים גם ב-C וב-C++. llvm-cov אינו מדווח על מורכבות, ולכן היא נספרת מנתוני ההסתעפויות שהדוח כבר נושא: התנאים שנכתבו בקובץ של הפונקציה עצמה, ועוד אחד — ההגדרה של McCabe, וזה מה שהכלים ברמת קוד המקור סופרים עבור .NET ו-Java. תנאים שנוצרו ממאקרו מקובץ אחר, למשל כל assert, אינם נספרים.
Screenshot pending — add assets/img/riskiest-methods.png (see SCREENSHOTS.md).Risk hotspots, ואילו קבצים להציג
מתחת לעץ של תצוגת Coverage, Risk hotspots מונה את הפונקציות שבהן קוד מורכב פוגש כיסוי מועט, הגרועות תחילה, וכל אחת פותחת את הקובץ שלה בפונקציה. פונקציה נכנסת לרשימה לפי ציון CRAP — hotspots.crapThreshold, 30 כברירת מחדל, הערך שמחברי המדד הציעו — או לפי מורכבות ציקלומטית בלבד, hotspots.complexityThreshold, כבוי כברירת מחדל; רק דוחות הנושאים מורכבות (OpenCover, Cobertura מ-Coverlet, JaCoCo, llvm-cov) מכילים כאלה. Community רואה את המספר ואת הציון הגרוע ביותר; הרשימה המדורגת היא ב-Pro. לצד המיון, רשימה נפתחת שנייה אומרת אילו קבצים העץ מציג — הכול, קבצים עם פערים, קבצים שלא נבדקו, או הקבצים שהשתנו מאז ההרצה האחרונה; תיקיות עוקבות אחר הקבצים שלהן ושומרות על המספרים שלהן. שניהם קיימים גם ב-Visual Studio, בחלון Coverage.
Screenshot pending — add assets/img/vs-hotspots.png (see SCREENSHOTS.md).מרחבי שמות, מחלקות ומתודות
לדוח .NET שמציין את המחלקות שלו — Cobertura ו-coverage.cobertura.xml של Coverlet, OpenCover — רשימה נפתחת שלישית, Folders / Namespaces, מציירת את אותה הרצה כמרחבי שמות, מחלקות ומתודות: המספר של מרחב שמות הוא סכום המחלקות שלו, של מחלקה — סכום המתודות שלה, בדיוק כפי שזה של תיקייה הוא סכום הקבצים שלה, עם אותו מיון ואותו מסנן. שורת מתודה פותחת את הקובץ במתודה; מחלקה שהוצהרה בלי מרחב שמות נמצאת תחת (no namespace). הבחירה נכתבת אל coverageView.perspective; להרצה שאינה נושאת שמות מחלקות אין רשימה נפתחת והיא מציגה את התיקיות שלה. ב-Visual Studio לחלון Coverage יש את אותה רשימה נפתחת.
Screenshot pending — add assets/img/namespace-perspective.png (see SCREENSHOTS.md).
חיפוש בעץ
מתחת לכפתורים ולרשימות הנפתחות, תיבת חיפוש. מילה משאירה את השורות ששמן או נתיבן מכיל אותה — כל מילה שהוקלדה חייבת להימצא; השוואה משאירה את השורות שהמספר שלהן עובר אותה — < 80% על הציון, lines >= 90, branches = 0, functions != 100, mcdc < 50 — ו-invoice < 80 דורש את שניהם. שורות המתודות של פרספקטיבת מרחבי השמות וה-risk hotspots מחופשים יחד עם הקבצים, כך שפונקציה נמצאת היכן שההרצה מחזיקה אותה. העץ מסונן תוך כדי הקלדה, בתוך העמוד, בלי ציור מחדש; תיקייה המכילה התאמה נפתחת בשבילה ונסגרת שוב כשהתיבה מתרוקנת; Esc מנקה אותה. אותה תיבה, אותו דקדוק, ב-Visual Studio.
Screenshot pending — add assets/img/tree-search.gif (see SCREENSHOTS.md).lines < 80.העץ עוקב אחרי העורך
הקובץ שאתם מסתכלים עליו מודגש בתצוגת Coverage, התיקיות שמעליו נפתחות והשורה שלו נגללת אל תוך התצוגה — כבר אין צורך לחפש בעץ את הקובץ שממילא פתוח. מלבד זאת העץ שומר על מיקום הגלילה שלו, ודבר אינו מצויר מחדש. coverageView.followActiveEditor, שמופעלת כברירת מחדל, מאפשרת לכבות זאת למי שמעדיף להשאיר את העץ היכן שהניח אותו.
Screenshot pending — add assets/img/follow-editor.gif (see SCREENSHOTS.md).
Screenshot pending — add assets/img/vs-follow-editor.gif (see SCREENSHOTS.md).11. בקרת עמידה בדרישות
פסק הדין COMPLIANT / NON-COMPLIANT (המוצג בתצוגת המקור המוער, בדוח ה-HTML ובשני חלוני הריחוף של שורת המצב) נקבע על פי ספי סף לכל מדד ומצב:
Screenshot pending — add assets/img/statusbar.png (see SCREENSHOTS.md).| מצב | COMPLIANT כאשר… |
|---|---|
strict (default) | כל מדד שנבדק בנפרד עומד בסף שלו — בלי פשרות. |
whm | הציון המשוקלל היחיד עומד ב־threshold.weighted. |
both | גם הבדיקה המשוקללת וגם הבדיקה הקפדנית לכל מדד מתקיימות. |
either | מתקיימת הבדיקה המשוקללת או הבדיקה הקפדנית לכל מדד (המקל ביותר). |
סף של 0 מכבה את השער הזה, ומדד שהדוח אינו נושא לעולם אינו נשפט. מה מייצג סף שלא הגדרתם — זאת קובע הפרופיל שלהלן. הריצו Fucini Coverage: Check Coverage Thresholds כדי להעריך לפי דרישה.
ב-Visual Studio. Tools → Coverage Studio → Check Coverage Thresholds שופט את ההרצה לפי אותם מפתחות threshold.* ואומר זאת בשורת המצב ובחלונית Output; עם compliance.diagnostics, problems.enabled, problems.perLine או deadCode.enabled הממצאים יושבים ב-Error List לצד אלה של המהדר עצמו — רשומה אחת לכל קובץ מתחת לסף, אחת לכל טווח לא מכוסה, אחת לכל פונקציה שמעולם לא רצה — וכל אחת פותחת את הקובץ שלה בשורה.
Screenshot pending — add assets/img/vs-error-list.png (see SCREENSHOTS.md).פרופילי ספים
threshold.profile קובע מה מייצג סף שלא הגדרתם. standard, ברירת המחדל מאז 0.2026.82, הוא מה שאפשר לדרוש מפרויקט רגיל שאינו קשור לבטיחות. safety פירושו כל שער על 100 — מה שתיק בטיחות (safety case) דורש, ובדיוק מה שסופק עד 0.2026.81.
| מדד | standard | safety |
|---|---|---|
| שורות | 80 | 100 |
| פונקציות | 80 | 100 |
| אזורים | 75 | 100 |
| הסתעפויות | 70 | 100 |
| הציון המורכב | 75 | 100 |
| MC/DC, מימושים, קריאות לפונקציות, קוד אובייקט | ללא שער | 100 |
| תנאים | ללא שער | 100 |
| ציון מוטציות | ללא שער | ללא שער |
סף שהגדרתם בעצמכם גובר על כל אחד מהפרופילים. בדוגמה השער של ההסתעפויות עומד על 90 וכל השאר על 100; כדי לדרוש 100 רק מחלק מהמדדים, הישארו ב-standard והגדירו אותם בעצמכם. הסתייגות אחת נובעת מאופן פעולתן של ההגדרות: ערך השווה לברירת המחדל המסופקת אינו ניתן להבחנה מהיעדר ערך, ולכן תחת safety סף שנכתב בדיוק כערך הסטנדרטי שלו — למשל 80 עבור שורות — עדיין נחשב ל-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).אם הסתמכתם על ברירות המחדל הישנות, לאחר העדכון ל-0.2026.82 תישפטו בצורה מקילה יותר עד שתבחרו ב-safety. התקנה שכבר רצה בעבר מקבלת על כך הודעה חד-פעמית, עם כפתור Keep 100% (safety) שכותב את הפרופיל להגדרות המשתמש שלכם; בפרויקט משותף הוסיפו אותו גם להגדרות סביבת העבודה, כדי שכולם יישפטו באותו אופן. ב-Configure Coverage Compliance & Thresholds... הפרופיל נמצא מעל רשת הספים, והתצוגה המקדימה החיה שופטת לפי השערים שבתוקף בפועל. בכל כרטיס ובכל דוח, מדד שהשער שלו כבוי מציג את ערכו עם קו מפריד ניטרלי במקום סימן וי או איקס.
Screenshot pending — add assets/img/statusbar-metrics.png (see SCREENSHOTS.md).11a. כיסוי קוד אובייקט
כל מדד אחר כאן נמדד מהמקור: כלי מבצע אינסטרומנטציה לקוד שלכם, הבנייה המאובזרת רצה, והמונים אומרים אילו פקודות, הסתעפויות או תנאים הופעלו. כיסוי קוד אובייקט מודד משהו אחר — כמה מהקובץ הבינארי שנבנה באמת רץ, בספירת בייטים של הוראות, על ידי התבוננות בזרם ההוראות ולא באמצעות אינסטרומנטציה של המקור. זה חשוב מפני שהמהדר פולט קוד שאף שורה במקור שלכם אינה אחראית לו: בדיקות גבולות של מערכים, טבלאות קפיצה של switch, שפיכת אוגרים, בדיקות מחסנית, קריאות לשגרות עזר של זמן ריצה לחילוק או לנקודה צפה בליבות שאין בהן ההוראה. זהו גם המדד היחיד כאן שעונה על השאלה האם זה מכסה אסמבלי? — אסמבלי שנכתב ביד לעולם אינו מאובזר, וכלי המבוסס על המקור אינו מגיע אליו. DO-178C מפורש לגבי הסיבה: ברמה A, כאשר מהדר או מקשר מייצר קוד שאינו ניתן למעקב ישיר אל פקודות המקור, יעד 6.4.4.2b דורש אימות נוסף בדיוק של הקוד המיוצר הזה.
הוא מכיל בתוכו את כיסוי הפקודות — כל הוראה שבוצעה מקורה בפקודה כלשהי, ולכן 100% כיסוי קוד אובייקט משמעו 100% כיסוי פקודות. ההפך אינו נכון, ואי-הסימטריה הזו היא כל העניין שבמדידה. משתי מסקנות נגזרות מכך. אין לו שום משקל בציון המשוקלל, משום שמיצוע שני מדדים של אותן הרצות סופר את אותה ראיה פעמיים; במקום זאת הוא נבדק מול הסף fuciniCoverage.threshold.objectCode — דרישה ולא משקל, בדיוק כפי שהתקן מבקש. וכן הפער הוא התוצר: הרצה עם 100% כיסוי שורות ופחות מ-100% כיסוי קוד אובייקט איתרה בדיוק את הקוד שיצר המהדר ושהמקור שלכם אינו אחראי לו, ולכן כרטיס העמידה בדרישות אומר 312 בייטים מעולם לא רצו, עם 100% כיסוי שורות במקום להסתיר זאת כ«94%». ההפך — קובץ בינארי שלם המדווח כמי שרץ בעוד המקור שלו לא — הוא סתירה ולא ציון נמוך: כמעט תמיד קובץ מעקב מיושן בצד אחד של מיזוג, או שמות מודולים שמעולם לא התאימו לנתיבי קבצים. הדבר מדווח כממצא.
כיסוי קוד אובייקט מחייב שהקובץ הבינארי ירוץ במקום שבו אפשר לצפות בהוראותיו. יש שלוש דרכים, והן שונות זו מזו עד מאוד בעלות. רק השלישית מפיקה כיסוי קוד אובייקט; שתי הראשונות מופיעות כאן משום שהן פותרות בעיה קרובה — לעיתים קרובות זו שבאמת כדאי לפתור.
- בנייה מאובזרת שרצה על היעד. מהדרים צולבים של GCC מקבלים
-fprofile-arcs -ftest-coverage, ולכן האבזור שעובד בתחנת עבודה עובד גם על היעד — אלא שלמערכת ללא מערכת הפעלה אין מערכת קבצים שאליה לכתוב את מוני.gcda, ולעיתים קרובות איןexit()שבו לכתוב אותם. המונים נמצאים בזיכרון בכל מקרה, ולכן הפתרון הוא לשפוך את הזיכרון הזה ולבנות מחדש את הקבצים מחוץ ליעד;embedded-gcovשל NASA JPL (רישיון Apache-2.0) עושה בדיוק את זה, בלי מערכת קבצים, בלי מערכת הפעלה ובלי ספריית C תקנית. זה נותן כיסוי פקודות, הסתעפויות ופונקציות של בנייה שיצר המהדר הצולב שלכם, עבור ערכת ההוראות שלכם, על החומרה שלכם — לא כיסוי קוד אובייקט, והקובץ הבינארי הנמדד מאובזר, כלומר גדול ואיטי מזה שאתם מספקים. את התוצאה טענו כ-LCOV, gcovr JSON, gcov JSON או, בשרשרת כלים ישנה מ-GCC 9, כרשימת הטקסט.gcov. - סימולטור ערכת הוראות. הריצו את הקובץ הבינארי האמיתי של היעד בסימולטור וגזרו כיסוי מהכתובות שבוצעו: בלי חומרה, בלי אבזור, בלי גשש — ומכיוון שהוא מתבונן בהוראות, הוא יכול להפיק כיסוי קוד אובייקט אמיתי. המגבלה היא נאמנות: סימולטור מדגמן את הליבה היטב ואת הציוד ההיקפי פחות, ולכן התייחסו בחשד לתוצאות ברמת המערכת כולה אלא אם הוא מדגמן את השבב שלכם מקרוב.
- מעקב על השבב ומנפה שגיאות. המסלול ברמת ההסמכה, והיחיד שאינו פולשני באמת: יחידת המעקב של הליבה מדווחת את זרם ההוראות למנפה שגיאות, שהופך אותו לכיסוי. דבר אינו מאובזר, גודל הקוד אינו משתנה והתזמון אינו נפגע — וזה בדיוק מה שהופך את התוצאה לראיה על הקובץ הבינארי שאתם באמת מספקים. בדקו את השבב לפני שתתקצבו זאת: במשפחות רבות של בקרים זעירים מעקב מלא זמין רק בגרסת אמולציה או פיתוח בעלת מאגר מעקב גדול ויציאת מעקב מהירה, בעוד רכיבי ייצור חושפים יחידת מעקב מצומצמת, שהפתרון החלופי של היצרן עבורם הוא מעקב תוכנה המאבזר את הקוד וצורך זמן מעבד — ובכך מבטל בדיוק את התכונה שבגללה נבחר המסלול.
פרויקטים מוטמעים רבים מודדים כיסוי על ידי הידור אותם מקורות עבור מחשב הפיתוח והרצת בדיקות היחידה שם. זה מהיר, אינו דורש חומרה, וזו ברירת המחדל הנכונה עבור רוב הצוותים — אך כדאי להיות ברורים לגבי מה שהראיה הזו בעצם מתארת: מהדר שונה, מְמַטֵּב שונה, ערכת הוראות שונה וקובץ בינארי שונה מזה שמסופק. עבור רוב התוכנה זהו פשרה מקובלת ומובנת היטב. עבור עבודה הנבחנת מול IEC 61508, ISO 26262 או DO-178C זו ההתנגדות הרגילה של מארח מול יעד, והמסלולים לעיל הם התשובות הרגילות לה — הראשון סוגר אותה עבור כיסוי המקור, השלישי עבור קוד האובייקט.
כיום היצוא הנקרא עבור קוד אובייקט הוא זה של COVerage.EXPORT.ListModule של Lauterbach TRACE32 עם metric="object"; טענו אותו כמו כל קובץ מעקב אחר. המדד הזה מנוקד ונבדק רק ברישיון בתשלום ובמהלך תקופת ההערכה. התקנת Community אינה מנקדת אותו — אך היא מקבלת הודעה כאשר קובץ מעקב מכיל אותו, משום שפסק עמידה בדרישות שהיה משמיט בשקט את הראיה החזקה ביותר בקובץ היה גרוע יותר מפסק שאומר מה השמיט.
12. אי-הכללת שורות שאינן קוד
עם excludeComments מופעל (ברירת המחדל), הצהרות הנופלות לחלוטין על שורות הערה בלבד או ריקות אינן נכללות בסכומים — זה גם מנטרל תופעה ידועה של llvm-cov/gcov שבה ספירת פגיעה תועה נוחתת על הערה. מסמנים סטנדרטיים גם מכובדים:
x = risky(); // LCOV_EXCL_LINE
// LCOV_EXCL_START
debug_only_block();
// LCOV_EXCL_STOP
גם הנחיות קדם-מעבד אינן נחשבות קוד, ב-C, C++, Objective-C, CUDA ו-C#: שורה שמתחילה ב-# — #define, #include, #if — והשורות שלוכסן הפוך בסופה ממשיך אותה אליהן. gcov מייחס כל שימוש במאקרו לשורה שבה הוא מוגדר, ולכן קובץ כותרת שהשורה היחידה שדווחה בו הייתה #define CHANNEL_COUNT (33U) נראה מכוסה ב-100% כי לולאה בקובץ ה-.c רצה עד אליו, וקובץ שאיש לא השתמש בקבוע שלו נראה ב-0%. לקובץ כותרת כזה אין עכשיו מה למדוד, והוא אינו מופיע ברשימה.
הגדירו excluded.includeInTotals ל-true כדי לספור בכל זאת שורות שהוחרגו.
השארת קובץ או תיקייה בחוץ, מתוך העץ
לחצו לחיצה ימנית על קובץ או תיקייה בתצוגת Coverage ובחרו Exclude from Coverage — הוא נמצא גם בין פעולות הנתיב של השורה — או הריצו Exclude This File from Coverage על הקובץ הפתוח: הנתיב של הקובץ יחסית לסביבת העבודה, או ה-/** של התיקייה, נכנס אל fuciniCoverage.ignore בהגדרות התיקייה, פעם אחת, והטעינה מחדש מוציאה אותו מכל סיכום ומכל עמוד; התבנית שם כדי שאפשר יהיה להוציא אותה שוב. ב-Visual Studio לתפריט השורה ול-Tools → Coverage Studio יש את אותן שתי פקודות, הכותבות את אותה הגדרה לאותו קובץ.
Screenshot pending — add assets/img/exclude-from-tree.gif (see SCREENSHOTS.md).
fees.ts — העץ בלעדיו, והתבנית ב-.vscode/settings.json.אטריבוטים ומרחבי שמות, ל-.NET
שתי הגדרות קוראות מתוך המקור את מה שהדוח אינו יכול לומר. ignore.attributes — ExcludeFromCodeCoverage כברירת מחדל — מחריגה את המחלקה, המתודה או המאפיין שמתחת לאטריבוט שהיא מציינת, כפי ש-LCOV_EXCL_START/STOP היו מחריגים, יהיה הכלי שכתב את הדוח אשר יהיה: Coverlet מכבד את האטריבוט, OpenCover, dotCover ו-lcov מומר לא, ועכשיו כולם מסכימים. שמות עם הסיומת Attribute או בלעדיה, עם מרחב שמות או בלעדיו; הוסיפו GeneratedCode, Obsolete או משלכם. ignore.namespaces משאירה בחוץ כל קובץ שהצהרת מרחב השמות שלו תואמת קידומת, * כתו כללי — Acme.Generated, Acme.*.Migrations, *Tests — וחלונית Output מציינת בשם את הקבצים שהיא לקחה. שתיהן נקראות באותו מעבר שקורא את סמני ההערות, בשתי המהדורות.
{
"fuciniCoverage.ignore.attributes": ["ExcludeFromCodeCoverage", "GeneratedCode"],
"fuciniCoverage.ignore.namespaces": ["Acme.Generated", "*.Migrations"]
}
החרגה מתוך העורך
סמנו את השורות וקחו Exclude Selection from Coverage מהנורה, מתפריט ההקשר של העורך או מ-Command Palette — ב-Visual Studio מהנורה (Ctrl+.), מתפריט הלחיצה הימנית של חלון הקוד, מ-Tools → Coverage Studio או Ctrl+Shift+U, X — וההחרגה נכתבת במקום שבו הקוד נמצא: [ExcludeFromCodeCoverage] מעל מחלקה, מתודה או מאפיין של C#, VB או F#, בשמו הקצר כשהקובץ כבר מייבא את System.Diagnostics.CodeAnalysis ובשם מלא כשאינו מייבא, כך שלא יהיה צורך להוסיף שום using; LCOV_EXCL_LINE בסוף שורת קוד אחת; LCOV_EXCL_START ו-LCOV_EXCL_STOP סביב כמה שורות, בהזחה של השורה הראשונה — עם סימן ההערה של השפה עצמה, //, #, ', -- או ;. צעד ביטול אחד. הנורה מציעה זאת גם על שורה שרשומות Problems מסמנות כלא מכוסה. שורה שכבר סומנה, או איבר שכבר נושא אטריבוט, נשארים כפי שהם.
Screenshot pending — add assets/img/exclude-selection.gif (see SCREENSHOTS.md).
LCOV_EXCL סביב ענף, ואז [ExcludeFromCodeCoverage] מעל מתודה.ענפים בלבד, והמסמנים של gcovr
else הגנתי, default: ששום ערך אינו מגיע אליו, הזרוע שמהדר מוסיף בשביל חריגה: השורה רצה וצריכה להיספר, ורק את הענף שלה אי אפשר לקחת. LCOV_EXCL_BR_LINE ו-LCOV_EXCL_BR_START … LCOV_EXCL_BR_STOP מוציאים מהספירה את הענפים שבשורות שלהם ומשאירים בה את השורות. LCOV_EXCL_EXCEPTION_BR_LINE והאזור המקביל לו מוציאים עוד פחות — רק את הזרועות שחריגה מובילה אליהן, היכן שהדוח אומר אילו הן, כפי שעושה ה-JSON של gcov. כל מסמן מזוהה גם בקידומות של gcovr: GCOVR_EXCL_LINE, GCOVR_EXCL_START, GCOVR_EXCL_BR_LINE, GCOV_EXCL_STOP והשאר פירושם כפירוש המסמנים שמתחילים ב-LCOV_EXCL_, כך שקוד מקור שנכתב ל-gcovr מתפרש כאן באותו אופן, יהיה הכלי שיצר את הדוח אשר יהיה. מה שאינו מזוהה: GCOVR_EXCL_FUNCTION — שום דבר בשורה הזו אינו אומר היכן הפונקציה מסתיימת.
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).לומר מדוע: החרגות מנומקות
הוצאת קוד מהספירה היא טענה — "את זה אי אפשר לבדוק", "זה כלי עזר למפתחים" — ולפי DO-178C, ISO 26262 או IEC 61508, טענה שמשנה את המספר שתעודת הסמכה נשענת עליו חייבת להיות כתובה וניתנת לסקירה. לכן החרגה יכולה לומר מדוע, במקום שבו היא כתובה: הטקסט שאחרי LCOV_EXCL_LINE או LCOV_EXCL_START, או ה-Justification של [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) { /* … */ }
את הנימוקים קוראים בכל טעינה, והיומן סופר אותם. Export Coverage Report… כותב את הרשימה — החרגות והנימוקים שלהן, כ-Markdown או כ-CSV: הקובץ, השורות, אופן הכתיבה, והנימוק או none given. קובץ שלא נשאר בו דבר שאפשר למדוד עדיין מופיע ברשימה הזו. כש-exclusions.requireReason מופעל, החרגה שאינה נותנת נימוק היא ממצא: אזהרה ב-Problems בשורה שלה, וכישלון של Check Coverage Thresholds. Exclude Selection from Coverage מבקש אז קודם את הנימוק וכותב אותו עם המסמן או כ-Justification של האטריבוט; אם הבקשה נסגרת או נשארת ריקה, דבר אינו מוחרג.
Screenshot pending — add assets/img/justified-exclusions.png (see SCREENSHOTS.md).
Screenshot pending — add assets/img/vs-justified-exclusions.png (see SCREENSHOTS.md).12a. האם הכיסוי הזה עדיין מתאר את הקובץ הזה?
כיסוי שנקרא מקובץ מעקב מתאר את הקוד כפי שהיה כשהטסטים רצו, ורוב הפורמטים אינם אומרים באיזו גרסה מדובר. לכן כל קובץ בלוח הכיסוי נמצא באחד משלושה מצבים:
- ✓ אומת — קובץ המעקב מתעד מה הכילה כל שורה שנמדדה, וזה עדיין תואם לקובץ.
- ללא סימון — לא הופרך. שום דבר אינו סותר את הכיסוי ושום דבר אינו מאשר אותו. זהו המצב הרגיל.
- ⚠ הופרך — הקובץ עצמו מפריך את הכיסוי שלו. השורה מעומעמת והחלונית מסבירה מה נמצא.
רק שני פורמטים יכולים לזכות בסימון, מפני שרק שניים מתעדים משהו על הקוד שמדדו: lcov שנכתב עם --checksum (כבוי כברירת מחדל ב-geninfo; מטרתו המתועדת היא בדיוק למנוע שילוב כיסוי משתי גרסאות של קובץ) ו-GNATcoverage XML, המשבץ את הטקסט של כל שורה שנמדדה. כדאי להפעיל את האפשרות ב-lcov.
האזהרה אינה זקוקה לאף אחד מהם ועובדת עם כל פורמט: כיסוי שנרשם מעבר לסוף הקובץ, פונקציה בשם שכבר אינה במקום שהדוח מציב אותה, או שורות שבוצעו והן ריקות בקובץ. חותמות זמן לבדן לעולם אינן מספיקות — git checkout משנה את כולן בלי לשנות בית אחד — ולכן חותמת זמן שהשתנתה היא לכל היותר סיבה להביט שוב. הבדיקה רצה בעת טעינת הכיסוי ושוב בכל פעם שקובץ נשמר או משתנה בדיסק, כך שהסימון עוקב אחרי הקובץ: עריכה שסותרת את ההרצה מציבה אותו, checkout שמשחזר את הגרסה שנמדדה מסיר אותו. התיאור אומר בדיוק מה הוכיח זאת. הגדירו את staleWarning.enabled ל-false כדי לכבות את כל זה.
12b. לא נמדד לעומת לא מכוסה
קובץ שההרצה מעולם לא מזכירה הוא לא נמדד: שום בדיקה לא טענה אותו, ולכן שום כלי לא כתב עבורו שורה. זה לא אותו דבר כמו לא מכוסה — נמדד, עם אפס פגיעות — וההרחבה מעולם לא ניקדה קובץ נעדר כ-0%. מה שהיא לא עשתה, עד 0.2026.69, הוא להציג את הנעדרים בכלל: מודול ללא שום בדיקה מעולם לא הופיע בעץ, בסיכומים או בבדיקת הסף, והקורא ראה „92%“ עבור פרויקט שמחצית מקבציו מעולם לא הופעלו.
כעת, עם הרצה טעונה, פריט שורת המצב לכל קובץ אומר לא נמדד עבור קובץ מקור מהסוג של ההרצה עצמה שההרצה אינה מכילה — „מהסוג של ההרצה“ פירושו שיש לו אחת מסיומות הקבצים שההרצה מדדה, כך שקובצי הכותרת והמקור של פרויקט C הם מועמדים וסקריפטי ה-Python שלו אינם. כל מה שמעבר לזה הוא לפי בחירה דרך fuciniCoverage.unmeasured.mode:
off(ברירת מחדל) — שום דבר אחר אינו משתנה.list— תצוגת הכיסוי מקבלת קבוצת לא נמדדו בתחתית שמציינת כל קובץ כזה, וכל שורה פותחת אותו; תוצאת הטעינה סופרת אותם; התגים מסמנים אותם ב-?ב-Explorer; ו-fuciniCoverage.threshold.unmeasuredFilesיכול להכשיל את Check Coverage Thresholds כשיש יותר ממספר שקבעתם. שום אחוז אינו זז.count— כל מה ש-listעושה, ובנוסף כל קובץ שלא נמדד נספר גם נגד ההרצה כקובץ לא מכוסה של שורות הקוד שלו, כך ששורת המצב, ספי הסף, התגים, ההיסטוריה, כל ייצוא ותצוגת Test Coverage מציגים את המספר הנמוך יותר. הקובץ מצויר כלא נמדד בכל מקום שבו הוא מופיע, פסי השוליים שלו אומרים „לא נמדד“ ולא „מעולם לא רץ“, ובדיקת אי-ההתאמה מניחה לו — אין מדידה שתוכנו יכול לסתור.
{
"fuciniCoverage.unmeasured.mode": "list",
"fuciniCoverage.threshold.unmeasuredFiles": 0
}
קובצי כותרת הם החיובי-השגוי הידוע ב-C: יש להם את משפחת הסיומות של ההרצה, ושום קובץ מעקב לעולם לא יציין אחד מהם, מפני שבפני עצמו הוא מתקמפל ללא כלום. fuciniCoverage.unmeasured.exclude משאיר לכן בחוץ כברירת מחדל את **/*.h, **/*.hpp, **/*.hh, **/*.inl ו-**/*.d.ts, באותו תחביר glob כמו fuciniCoverage.ignore; הוסיפו פורט לפלטפורמה שאינו נבנה כאן, או stubs שנוצרו אוטומטית, והם יוצאים מהרשימה, מהספירה וממצב שורת המצב. גם קובץ ש-ignore מציין לעולם אינו נקרא „לא נמדד“ — להשאיר אותו בחוץ היה כל העניין. threshold.unmeasuredFiles הוא כברירת מחדל -1, שאינו בודק; 0 נכשל ברגע שקובץ כלשהו מהסוג של ההרצה מעולם לא נטען על ידי בדיקה, והוא חל רק כל עוד unmeasured.mode הוא list או count.
13. דוחות HTML
- Generate Full HTML Report — דוח מרובה עמודים, לכל ספרייה, המעובד עצמאית. הפלט הולך אל
htmlReport.outputDir, או לאחסון הגלובלי של התוסף כשלא הוגדר. - Open Annotated Source — תצוגה מוערת לקובץ בודד. הפנו את
externalHtmlReport.dirלתיקייתllvm-cov show --format=htmlשנבנתה מראש כדי להשתמש בעמודים אלו במקום ברינדור המובנה. - Export Fucini JSON — המודל המנורמל המלא לכלים שלכם.
- Export Coverage Report... — ההרצה כ-CSV (לכל קובץ או לכל פונקציה), סיכום Markdown, קובץ מעקב LCOV, Cobertura XML, SARIF, או תג SVG עצמאי ל-README שלכם. נגיש גם מהכפתור שליד Generate Full HTML Report בתצוגת Covered Files. הכול מלבד ה-CSV מאבד מידע — ל-MC/DC, לאזורים ולהיווצרויות אין מקום ב-LCOV, ב-Cobertura או ב-SARIF — ולכן Fucini JSON וה-CSV נשארים הפורמטים שנושאים כל מדד.
- Copy Uncovered Lines — סיכום Markdown של כל פער, מוכן להדבקה ב-PR.
ב-Visual Studio. קבוצת Reports של Tools → Coverage Studio: Show Annotated Source פותח את המסמך הפעיל כעמוד באזור המסמכים — כל שורה בצבעה, הממצאים לצדה — הנגלל יחד עם העורך בשני הכיוונים; Open HTML Report כותב את הדוח בן העמוד האחד אל htmlReport.outputDir (או אל %LOCALAPPDATA%\Fucini\CoverageStudio\html-report) ופותח את הדפדפן; Generate Full HTML Report כותב לשם את האינדקס לכל תיקייה ואת העמוד לכל קובץ; Export Coverage Report… מציע את אותם שמונה פורמטים ושואל היכן לשמור; Generate Coverage Badge כותב את התג למקום ש-badge.outputPath מציין, אחרי כל טעינה עם badge.autoUpdate. העמוד המוער זקוק ל-WebView2, כמו חלון Coverage; הדוחות בדיסק אינם זקוקים לו.
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).קוד מקור עם הערות לעומת קוד מקור רגיל
Open Annotated Source מחליף את הכרטיסייה הפעילה בתצוגת web צבעונית של הכיסוי עבור אותו קובץ, באותה עמודה; Open Annotated Source to the Side עושה את אותו הדבר אך בפיצול, כך שהמקור והתצוגה עם ההערות יושבים זה לצד זה. כדי להחליף במקום במקום זאת — שימושי במסך קטן שבו פיצול הופך כל חלונית לצרה מדי — השתמשו ב-Toggle Annotated Source: היא מחליפה את הכרטיסייה הפעילה בין השתיים, וזוכרת באיזו מהן אתם צופים כרגע. מתוך התצוגה עם ההערות עצמה, Show Source קופצת ישירות בחזרה לעורך הרגיל של אותו קובץ.
איזה HTML תראו בפועל תלוי ב-externalHtmlReport.dir: כאשר הוא מוגדר וכבר קיימת שם עמוד התואם לקובץ הפעיל (llvm-cov מסדר עמודים לפי קובץ בתור <שם-repo>/<נתיב-יחסי>.html, כך שתיקיית שם ה-repo של הדוח לעולם אינה זקוקה להגדרה), אותו עמוד שנוצר על ידי שרשרת הכלים מוצג במקום מנוע העיבוד המובנה — הקישורים/גיליון הסגנונות המקומיים שלו נכתבים מחדש כדי לפעול בתוך ה-webview, והוא כולל פרטים שהתצוגה המובנית אינה משחזרת (תצוגות הרחבת MC/DC, הדגשת אזורים, סיכומי ספריות). אין עמוד תואם לאותו קובץ, או שההגדרה נותרה ריקה? אז נעשה שימוש במנוע העיבוד המובנה. התוסף רק קורא מתיקייה זו — הוא לעולם אינו כותב אליה.
תג כיסוי ל-README
Generate Coverage Badge כותב SVG בסגנון shields להרצה הפעילה אל תוך סביבת העבודה — badge.outputPath, ברירת מחדל coverage-badge.svg, יחסית לתיקיית סביבת העבודה או מוחלט, עם אותם משתנים כמו כל הגדרת נתיב אחרת — ומציע לפתוח אותו. זהו קובץ רגיל במאגר שלכם, ולכן README מטמיע אותו בלי שירות מאחוריו, בלי הלוך-ושוב אל shields.io, וזה עובד גם במאגר מנותק מהרשת:

badge.metric בוחר מה התג מציג: lines (עם התווית coverage), branches, mcdc או weighted, אותו ציון מורכב ששורת המצב מציגה, עם התווית score. הרצה ללא נתונים למדד שנבחר מקבלת n/a אפור ולא 0% אדום. הצבע עוקב אחרי מדרגות ה-colorScale.* שלכם: lowColor מתחת ל-lowThreshold, midColor עד highThreshold, highColor משם והלאה. עם badge.autoUpdate מופעל, התג נכתב מחדש אחרי כל טעינה מוצלחת, בשקט, וערוץ הפלט רושם כל כתיבה כ-[FUCINI_BADGE] — כבוי כברירת מחדל מפני שהוא כותב לסביבת העבודה בכל טעינה. בצעו commit ל-SVG יחד עם הקוד, והתמונה בעמוד המאגר עוקבת אחרי המספר שבעורך.
{
"fuciniCoverage.badge.outputPath": "docs/coverage-badge.svg",
"fuciniCoverage.badge.metric": "weighted",
"fuciniCoverage.badge.autoUpdate": true
}
14. היסטוריה ומגמות
הפעילו את history.enabled כדי לשמר הרצות באופן מקומי (תוך שמירה על history.retention מהן). לאחר מכן תקבלו חץ מגמה (▲/▼) בשורת המצב, את תרשים המגמה בתצוגת Coverage, ושתי פקודות השוואה: Compare with Last Run ו-Compare Two History Runs, כל אחת מייצרת דיפרנציאל נסיגה/שיפור לכל קובץ.
ב-Visual Studio. כל טעינה מושווית לזו שלפניה: משולש בשוליים בכל שורה שהתחילה או הפסיקה לרוץ (sinceLastRun.enabled), המגמה לצד הציון בשורת המצב, ו-Compare with Last Run לקבצים שמספריהם זזו. עם history.enabled ההרצות נשמרות תחת %LOCALAPPDATA%\Fucini\CoverageStudio\history, history.retention מהן, כך שההשוואה שורדת הפעלה מחדש, לתרשים המגמה יש מה לצייר, ו-Compare Two History Runs… בוחר כל שתיים מהן.
Screenshot pending — add assets/img/history-compare.png (see SCREENSHOTS.md).
Screenshot pending — add assets/img/since-last-run.png (see SCREENSHOTS.md).תרשים המגמה
מתחת לסרגל הכלים של תצוגת Coverage, עם שתי הרצות שמורות או יותר, כיסוי השורות של ההיסטוריה כקו, מהישנה לחדשה, שלושים החדשות ביותר: נקודה לכל הרצה שאומרת בריחוף את התאריך והמספר שלה, והמספר האחרון לצדה עם חץ לכיוון מאז הראשונה. הסקאלה האנכית היא הטווח של ההרצות עצמן, כך שצוות שנמצא ב-92–94% רואה את התנועה ולא קו שטוח מתחת ל-100. שתי המהדורות מציירות אותו מאותה היסטוריה.
Screenshot pending — add assets/img/trend-chart.png (see SCREENSHOTS.md).
סשנים של כיסוי
הרצת בדיקות אחת מכסה רק לעתים נדירות את כל מה ששינוי נגע בו: בדיקות היחידה רצו כאן, חבילת האינטגרציה שם, מעבר בממשק המשתמש עם כיסוי מופעל במקום אחר. Start Coverage Session הופך את הטעינות שאחריו לסכום אחד — כל הרצה מתווספת לקודמתה שורה אחר שורה כאיחוד, שורה שאחת מהן הריצה היא מכוסה והספירות מצטברות — כך שהשוליים, העץ והציון מראים מה כולן הגיעו אליו יחד. ההרצה שעל המסך, אם יש כזו, היא הראשונה של הסשן. פס מעל העץ אומר כמה הרצות ומאז מתי ומסיים את הסשן; End Coverage Session עושה את אותו הדבר, והטעינה הבאה עומדת שוב לבדה. ב-Visual Studio רשומה אחת תחת Tools → Coverage Studio מתחילה את הסשן, וכשהיא מסומנת, מסיימת אותו.
Screenshot pending — add assets/img/coverage-session.gif (see SCREENSHOTS.md).
קו הבסיס של ה-CI: איפה אני עומד מול main?
Compare with Last Run עונה מה השינוי האחרון שלכם עשה; לפני pull request השאלה היא איפה אתם עומדים מול main, והתשובה נמצאת בשרת ה-build. baseline.report מציין את הדוח שה-build של הענף הראשי מפרסם, וכל טעינה מושווית אליו: כרטיס שורת המצב נושא את ההפרש בשורה אחת — vs CI baseline: 84.20% → 85.10% (+0.90%), 3 file(s) moved — ו-Compare with CI Baseline מונה את הקבצים שזזו, קובץ אחר קובץ, באותן מילים כמו Compare with Last Run. ב-Visual Studio הפקודה נמצאת תחת Tools → Coverage Studio ושולפת או קוראת את הדוח כשאתם מבקשים. שלוש דרכים לציין אותו, ב-.vscode/settings.json:
- כתובת URL שה-CI מגיש. GitLab שומר את ה-artifacts של ה-job האחרון של ענף בכתובת יציבה; האסימון נשאר מחוץ לקובץ ההגדרות באמצעות
${env:…}ב-remote.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.infoעםAuthorization: Bearer ${env:TC_TOKEN}. כתובת ה-URL נשלפת ונשמרת במטמון בדיוק כפי שכתובת URL ב-coverageFile.pathsנשמרת (ETag,remote.refreshMinutes). - קובץ שה-pipeline העתיק לשיתוף רשת — נתיב מוחלט כמו
\\build\drops\app\main\coverage.cobertura.xml. - artifact שהורד ונשמר תחת התיקייה, נניח
ci/main.lcov.info(הכניסו את התיקייה ל-.gitignore) — נתיב יחסי לתיקייה.
{
"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}"]
}
כל פורמט שהקורא מכיר יתאים. נתיב שה-CI כתב יחסית ל-checkout שלו — src/Billing/Invoice.cs, כפי ש-Coverlet כותב אותו על ה-runner — ממוקם תחת התיקייה הזו לפני ההשוואה, כך שהוא פוגש את הקובץ שההרצה המקומית פתרה; נתיב מוחלט ממחשב אחר אינו תואם דבר, אז דאגו שה-pipeline יכתוב נתיבים יחסיים. קו בסיס שאי אפשר לשלוף או לקרוא הוא שורה בחלונית Output, לעולם לא טעינה כושלת.
Screenshot pending — add assets/img/ci-baseline.gif (see SCREENSHOTS.md).main.
artifact הוא קובץ zip, וגם אותו קוראים. GitHub ו-GitLab מוסרים artifact כארכיון, יהיה מה שהוכנס לתוכו אשר יהיה. ציינו את שם הדוח שבתוכו אחרי #: הקובץ שבארכיון מאותר לפי הנתיב שלו או לפי סופו; בלי # זהו הקובץ היחיד בארכיון, או הקובץ היחיד בו שנראה כמו דוח, וכשיש כמה כאלה חלונית Output מציינת את שמותיהם. הדבר נכון גם לקובץ zip שהורדתם (ci/artifact.zip#lcov.info) וגם, ב-VS Code, לכתובת URL ב-coverageFile.paths. האסימון נשלח לשרת שעבורו הוגדר ולא הלאה: ההפניה אל האחסון שמחזיק את הארכיון נעשית בלעדיו.
{
"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. לסוכני AI: הכיסוי שעל המסך
סוכן שכותב בדיקות יכול להריץ אותן ולקרוא אחוז. מה שהוא אינו יכול לעשות בעצמו הוא לשאול מה העורך יודע: אילו שורות של הפונקציה הזו מעולם לא רצו, איזה צד של איזה ענף, אילו בדיקות מריצות שורה, האם ה-diff שכתב זה עתה מכוסה. שישה כלים עונים בדיוק על כך, במילים שסוכן יכול לפעול לפיהן, מתוך ההרצה הטעונה — אותן החרגות, אותו מיפוי מחדש, אותם מספרים שעל המסך. כך סוכן שהתבקש לכסות את הפערים של פונקציה, וסוקר שמסתכל על השוליים, מדברים על אותן שורות.
| כלי | על מה הוא עונה |
|---|---|
coverage_summary | הסיכומים של ההרצה לכל מדד, והקבצים הרחוקים ביותר מכיסוי מלא. הדבר הראשון שכדאי לשאול. |
coverage_gaps | מה שמעולם לא רץ בקובץ, בפונקציה או בטווח שורות: השורות הלא מכוסות, זרועות הענפים שלא נלקחו, תנאי ה-MC/DC שחסר להם הזוג שלהם, המוטנטים ששרדו. |
tests_for_line | אילו בדיקות הריצו שורה, היכן שהדוח אומר זאת — הרצה לפי בדיקה. |
patch_coverage | הכיסוי של diff — עץ העבודה מול ref, או patch שנמסר — והשורות שלו שמעולם לא רצו. |
coverage_delta | מה השתנה מאז ההרצה הקודמת: הסיכומים, והקבצים שהרוויחו או הפסידו כיסוי. |
test_run_command | הפקודה שמריצה את הבדיקות של סביבת העבודה הזו עם כיסוי מופעל. הסוכן מריץ אותה; העורך טוען מחדש את הדוח בעצמו. |
הסוכן של VS Code עצמו מקבל אותם ככלים בלי שצריך להגדיר דבר. כל שאר הסוכנים — כל לקוח שמדבר MCP, ה-Model Context Protocol — ניגשים אליהם דרך שרת שהעורך מריץ כאשר mcp.enabled מופעל, ב-VS Code וב-Visual Studio כאחד. Copy MCP Server Configuration מעתיק ללוח את הרשומה של הלקוח, בצורה שבה VS Code ו-Visual Studio קוראים אותה בקובץ mcp.json; לקוח שקורא למפתח ה-JSON החיצוני mcpServers מקבל את אותה רשומה תחת השם הזה.
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 …" }
}
}
}
- הוא כבוי כל עוד לא הפעלתם אותו, ומאזין ב-
127.0.0.1בלבד: שום דבר מחוץ למחשב הזה אינו מגיע אליו. - קריאה חייבת לשאת את האסימון שלכם, שנוצר פעם אחת ונשמר בשבילכם; בלעדיו התשובה היא 401. התצורה שהועתקה מכילה את האסימון: אל תכניסו אותה למאגר הקוד.
- קריאה ששלח דף אינטרנט — היא מצהירה על כך ב-
Originשלה — נענית בסירוב, יהיה מה שהיא נושאת אשר יהיה. - הוא קורא את ההרצה הטעונה ואינו כותב דבר. הרצת הבדיקות אינה מופעלת, רק הפקודה שלה נמסרת: הסוכן מריץ את הפקודה בטרמינל שלו.
הפורט הוא mcp.port, 39217 אם לא הוגדר אחרת. כשהוא תפוס — חלון שני, המהדורה האחרת לצד זו — נעשה שימוש בפורט הפנוי הבא, והתצורה שהועתקה מציינת את הפורט שעובד. חלונית Output אומרת היכן השרת מאזין ([FUCINI_MCP]) ומדוע לא הצליח להאזין ([FUCINI_MCP_001]). את מה שתוכנית אינה כוללת — שמות הבדיקות, פירוט ה-MC/DC — הכלים סופרים בלי לפרט, כפי שעושה הריחוף.
15. הפניית פקודות
ב-Visual Studio. כל פקודה נמצאת תחת Tools → Coverage Studio, בשם שבטבלה ללא הקידומת Fucini Coverage:; סרגל הכלים של חלון Coverage ותפריט הלחיצה הימנית על שורה מכילים את אלה ששייכות לשם, ותפריט הלחיצה הימנית של חלון הקוד מכיל את שלוש הפועלות על העורך: Run This Test with Coverage, Show Tests That Ran This Line ו-Exclude Selection from Coverage. אלה עם מקשים הן אקורדים בשתי הקשות אחרי Ctrl+Shift+U: R טוען מחדש, N ו-P עוברים לשורה הלא מכוסה הבאה והקודמת, B להחלטה הבאה שנבדקה חלקית, T מונה את הבדיקות שהריצו את השורה, X מחריג את הבחירה — לא ה-Alt+N של VS Code, כי ב-Visual Studio Alt ואות פותחים תפריט. שנו אותם תחת Tools → Options → Keyboard, שם הם מופיעים כ-Coverage Studio: …. לא במהדורה זו: חלונית Test Coverage היא ממשק API של VS Code — ההרצה נמצאת במקום זאת בחלון Coverage — ו-Solution Explorer אינו יכול להציג תגים. רק במהדורה זו: Run Native Project with Coverage, לפרויקט הפעלה של C++.
ב-Visual Studio: איפה נמצא כל דבר. חלון Coverage נמצא תחת View → Other Windows → Coverage, וראשון תחת Tools → Coverage Studio, שם נמצאת כל פקודה של מהדורה זו, בקבוצות: טעינה וטעינה מחדש, מעקב אחר הקובץ, שתי פקודות ההעתקה והכרטיסים; Run Tests with Coverage, Run Native Project with Coverage ו-Collect Coverage in Test Explorer…; Next ו-Previous Uncovered וההחלטות שנבדקו חלקית; הצביעה, מוני ההרצות ומצבי השוליים; מקור הכיסוי של קובץ, הבדיקות שהריצו שורה, בדיקה אחת עם כיסוי, שתי דרכי ההחרגה; Compare with Last Run, Compare Two History Runs…, Compare with CI Baseline, סשן הכיסוי ו-Check Coverage Thresholds; קבוצת Reports — Show Annotated Source, Open HTML Report, Generate Full HTML Report, Export Coverage Report… ו-Generate Coverage Badge; ואז Getting Started, ספי התאימות ו-Licence…. סרגל הכלים של החלון עצמו מכיל את חמש הפקודות השימושיות ביותר: Load Coverage, Reload, Toggle Coverage Painting, Copy Coverage Summary וספי התאימות; מתחתיהן הפרספקטיבה, המסנן והמיון, ותיבת החיפוש; מתחת לאלה המגמה. השהו את המצביע על שורה בעץ ולחצו על ⋯ שלה לתפריט השורה — פתיחת הקובץ, פתיחת התיקייה שלו, העתקת הנתיב, מוחלט או יחסי, עם כל אחד משני סוגי הלוכסן, החרגתו מהכיסוי. בקצה הימני של שורת המצב נמצאים ציון ההרצה וציון הקובץ הפתוח, עם המגמה מאז ההרצה האחרונה; Show Coverage Card ו-Show Coverage Card for This File פותחים את הכרטיסים שמאחוריהם, אותם כרטיסים ש-VS Code מציג כשהמצביע נח על פריט שורת המצב שלו.







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).| פקודה | מה זה עושה |
|---|---|
| Load Coverage | לגלות ולטעון כיסוי לסביבת העבודה. כברירת מחדל Alt+Shift+R (Ctrl+Alt+R ב-macOS). |
| Pick Coverage File | בחרו קובצי מעקב — אחד, כמה, או עוד אחד בכל פעם; הבחירות מצטברות, ממוזגות ונכתבות ל-coverageFile.paths, כך שמעתה הן נטענות מעצמן. |
| Show Loaded Coverage Files | הצג את קובצי המעקב של ההרצה הפעילה. גם תצוגת הכיסוי מציגה אותם, כל אחד עם כפתור הסרה וכפתור בחירה לצידו. |
| Toggle Tracefile Watch | עקוב אחרי שינויים בקובצי המעקב וטען מחדש אוטומטית. |
| Run Tests with Coverage | זהה את מריץ הבדיקות, הרץ אותו עם כיסוי במשימת טרמינל, טען את מה שהוא כותב והצע להוסיף את הנתיב להגדרות. |
| Run This Test with Coverage | הבדיקה שמתחת לסמן — המתודה, המחלקה או בלוק ה-describe, או הקובץ — מורצת במתכון המצומצם אליה, ואז נטענת כמו כל הרצה. גם בתפריט ההקשר של העורך. |
| Show Tests That Ran This Line | היכן שהדוח אומר אילו בדיקות הריצו מה, מונה את הבדיקות שהריצו את השורה שמתחת לסמן, העמוסה ביותר תחילה, ופותח את זו שבחרתם במקום שבו היא כתובה. |
| Run Tests Affected by My Changes… | מציג ברשימה את הבדיקות שהריצו שורה שעץ העבודה משנה מול testImpact.baseRef, פותח את זו שבחרתם, או מריץ רק אותן היכן שהדוחות הגיעו מהרצה לפי בדיקה. |
| Show Minimal Test Set… | קבוצת הבדיקות הקטנה ביותר שעדיין מריצה כל שורה שחבילת הבדיקות מריצה, ואחריה הבדיקות שאינן מוסיפות אף שורה משלהן. |
| Run App with Coverage… | מפעיל את אפליקציית ה-.NET של התיקייה תחת dotnet-coverage, וטוען את מה שעברתם בו כשהיא נסגרת. |
| Run Mutation Tests Here | מחיל מוטציות על הפונקציה שהסמן נמצא בה — או על הבחירה, או על הקובץ — באמצעות Stryker.NET, StrykerJS או PIT, וטוען את הדוח לצד הכיסוי שעל המסך. |
| Exclude This File from Coverage / Exclude from Coverage | מכניס את הקובץ הפתוח — או, על שורה בתצוגת Coverage, את הקובץ או את ה-/** של התיקייה — אל fuciniCoverage.ignore בהגדרות התיקייה, פעם אחת. |
| Exclude Selection from Coverage | כותב את ההחרגה במקום שבו הקוד נמצא: [ExcludeFromCodeCoverage] מעל איבר .NET, LCOV_EXCL_LINE על שורה אחת, LCOV_EXCL_START/STOP סביב כמה שורות, בסימן ההערה של הקובץ עצמו. גם מהנורה ומתפריט ההקשר של העורך. |
| Start Coverage Session / End Coverage Session | כל עוד סשן פעיל, כל טעינה מתווספת לקודמתה כאיחוד; פס מעל העץ סופר את ההרצות ומסיים אותו. |
| Next / Previous Uncovered | לדלג בין אזורים לא מכוסים. כברירת מחדל Alt+N / Alt+P (Ctrl+Alt+N / Ctrl+Alt+P ב-macOS). |
| Choose Editor Gutter Mode... | כבוי, פסים על שורות לא מכוסות בלבד, פסים אדומים-ענבריים-ירוקים, או מפת חום של מספרי פגיעות בשוליים של העורך. |
| Cycle Editor Gutter Mode | צעד אחד קדימה בין off, uncovered, coverage ו-heatmap — Alt+G, או לחצן המצב בשורת המצב. |
| Choose Coverage Source for This File... | כשיותר מדוח טעון אחד מודד את הקובץ הפתוח, בחירה מאיזה מהם יבואו המספרים שלו, עבור הקובץ, התיקייה שלו או תבנית — כותב כלל coverageFile.sources. |
| Clear Coverage Source for This File... | הסרת כללי coverageFile.sources שחלים על הקובץ הפתוח. |
| Toggle Inline Hit Counts | להציג או להסתיר את מוני הביצוע ×N אחרי כל שורה — מחליף את hitCounts.inline. |
| Show in Test Coverage View | לפרסם את ההרצה הפעילה לחלונית Test Coverage של VS Code עצמו (גם כש-testCoverage.publish כבוי) ולפתוח אותה. |
| Suggest Path Remap Rule | להסיק את כלל ה-pathRemap שיתאים את הקבצים הלא-מותאמים של ההרצה הפעילה לסביבת העבודה, ולהציע להוסיף אותו. |
| What Community Includes | כל מגבלה וכל תכונה מנועה של הרמה החינמית ברשימה אחת, עם כמה מכל מגבלה נוצל. |
| Open HTML Report | לפתוח את הדוח הסטטי שנוצר. |
| Generate Full HTML Report | לבנות את הדוח מרובה־העמודים. |
| Open Annotated Source / …to the Side | תצוגת כיסוי מוערת לקובץ. |
| Toggle Annotated Source | להחליף בין המקור לתצוגה המוערת. כברירת מחדל Alt+A (Ctrl+Alt+A ב-macOS). |
| Show Worst-Covered Files / Folders / Functions | Quick Pick ממוין מהנמוך ביותר. |
| Copy Uncovered Lines | סיכום Markdown של כל טווח לא מכוסה. |
| Compare Two History Runs / with Last Run | הפרש רגרסיה לכל קובץ — שתי הרצות שההיסטוריה שמרה, או ההרצה שעל המסך מול זו שהיא החליפה. |
| Compare with CI Baseline | ההרצה הטעונה מול הדוח ש-baseline.report מציין — זה של הענף הראשי מה-CI, כתובת URL או artifact שהורד — קובץ אחר קובץ. |
| Show Indirect Coverage Changes… | השורות שהכיסוי שלהן השתנה אף שאיש לא ערך אותן, מול קו הבסיס של ה-CI או מול ההרצה הקודמת, לפי קובץ. |
| Check Coverage Thresholds | להעריך את בדיקות התאימות. |
| Export Fucini JSON | לייצא את ההרצה הנוכחית כ־Fucini JSON. |
| Export Coverage Report... | בחרו תבנית — CSV, Markdown, LCOV, Cobertura XML, SARIF או תג SVG — ויעד. |
| Generate Coverage Badge | לכתוב את תג ה-SVG של ההרצה הפעילה אל badge.outputPath, המציג את badge.metric, ולהציע לפתוח אותו. |
| Copy MCP Server Configuration | מעתיק ללוח את מה שלקוח MCP צריך כדי לשאול על הכיסוי שעל המסך — כתובת השרת והאסימון שלכם; כשהשרת כבוי, מציע להפעיל אותו. |
| Show Status Bar Menu | לפתוח את תפריט הפעולות המהירות. |
| Browse for External HTML Report / Full Report Output Dir… | להגדיר את תיקיות הדוחות באמצעות בורר. |
16. הפניית הגדרות
טבלת ההגדרות המלאה והמסווגת — כל אפשרות עם ברירת המחדל שלה — נמצאת בעמוד תכונות והגדרות. לכל המפתחות יש קידומת fuciniCoverage..
ראוי לציין: fuciniCoverage.language קובע את ממשק זמן־הריצה של התוסף עצמו (שורת המצב, התראות, תיאורי כלים, תצוגות web) לשפה מסוימת, ללא תלות בשפת התצוגה של VS Code — ברירת המחדל היא auto, וכולל חבילות לכל 18 השפות הנתמכות. הוא אינו משנה את פריטי לוח הפקודות או את התוויות בהגדרות, שאותן VS Code ממשיך לקבוע לפי שפת התצוגה שלו.
ב-Visual Studio. אותם מפתחות fuciniCoverage.*, הנקראים מעד ארבעה קבצים, כשהמאוחר גובר: הגדרות המשתמש של VS Code עצמו אם VS Code מותקן במחשב — נקראות, לעולם לא נכתבות, כך שהצבעים והספים שלכם באים איתכם; %APPDATA%\Fucini\CoverageStudio\settings.json, הגדרות המשתמש של מהדורה זו; .vscode\settings.json בתיקייה או לצד הפתרון, כך שמאגר שהוגדר ל-VS Code מוגדר ל-Visual Studio; ו-fucini-coverage.json בשורש הפתרון, לצוות שמעדיף לא להחזיק תיקיית .vscode במאגר .NET — גם מהדורת VS Code קוראת אותו. גלגל השיניים בסרגל הכלים של חלון Coverage פותח חלון הגדרות שכותב את קובץ המשתמש או את קובץ התיקייה הקיים, כפי שבורר Write changes to שלו אומר, ושומר את ההערות של קובץ שהוא עורך. fuciniCoverage.language עובד שם באותו אופן; התפריטים עוקבים אחר שפת Visual Studio עצמו.
17. קודי שגיאה
אבחונים עוברים לערוץ הפלט Fucini Coverage (View → Output → Fucini Coverage), כל אחד עם קוד FUCINI_* יציב.
ב-Visual Studio. אותם קודים הולכים לחלונית Fucini Coverage של חלון Output (View → Output) ונשמרים ב-%LOCALAPPDATA%\Fucini\CoverageStudio\coverage-studio.log, לשאלה שמגיעה אחרי שה-IDE נסגר. שלושה שצצים: שום דבר לא מסומן אף שהחלונית אומרת שקבצים נטענו — מצב השוליים הוא off, בחרו Show Coverage in Editor; FUCINI_REMAP_001 ופס מידע — הדוח מציין נתיבים שאינם קיימים כאן, והחלונית מציעה את כלל pathRemap; חלון Coverage אומר שהוא זקוק ל-WebView2 — התקינו את Microsoft Edge WebView2 Runtime, הסימונים בעורך אינם זקוקים לו.
| קוד | משמעות |
|---|---|
FUCINI_PARSE_001 | פורמט כיסוי שאינו נתמך/לא מזוהה — אף מנתח לא התאים לקובץ. |
FUCINI_PARSE_010 | בקובץ ה־lcov לא היו רשומות SF. |
FUCINI_PARSE_020 | ה־JSON של llvm-cov לא תקין, חסר data[], או שלא הכיל קבצים. |
FUCINI_PARSE_030 | שורש Cobertura <coverage> חסר או שה־XML לא תקין. |
FUCINI_PARSE_040 | שורש JaCoCo <report> חסר או שאין קובצי מקור. |
FUCINI_PARSE_050 | ה־JSON של Istanbul/SimpleCov לא תקין או שלא הכיל קבצים. |
FUCINI_PARSE_060 | ה־JSON של SimpleCov לא תקין או חסר מערך files ברמה העליונה. |
FUCINI_PARSE_070 | פרופיל Go ללא כותרת mode:, או ללא בלוקי כיסוי. |
FUCINI_PARSE_080 | חסר שורש Clover מסוג <coverage> או <project>, או שאין בו קבצים. |
FUCINI_PARSE_090 | חסר שורש OpenCover מסוג <CoverageSession>, או שאין בו קבצים. |
FUCINI_PARSE_100 | JSON של coverage.py אינו תקין או חסר אובייקט files ברמה העליונה. |
FUCINI_PARSE_110 | JSON של gcov/gcovr אינו תקין או חסר מערך files ברמה העליונה. |
FUCINI_PARSE_120 | קובץ GNATcoverage XML ללא רכיב <source>, או index.xml שה-xi:include שלו מעולם לא הורחבו — טענו במקומו את קובצי *.xml לכל קובץ מקור. |
FUCINI_PARSE_130 | רכיב השורש <BullseyeCoverage> חסר, או שאין בו רכיבי <src>. |
FUCINI_PARSE_140 | רכיב השורש <CoverageDSPriv> חסר, אין טבלת <SourceFileNames> לפענוח שורות, או שאין נתוני שורות. |
FUCINI_PARSE_150 | JSON כיסוי של Xcode אינו תקין, או חסר מערך targets ברמה העליונה. |
FUCINI_PARSE_160 | רכיב השורש <coverage> של SonarQube חסר, או שאין בו רכיבי <file>. |
FUCINI_PARSE_170 | JSON של Coveralls אינו תקין, או חסר מערך source_files ברמה העליונה. |
FUCINI_LOAD | טעינה בוטלה מהודעת ההתקדמות שלה; ההרצה הקודמת, אם הייתה, נשארת טעונה. |
FUCINI_REMOTE_001 | לא ניתן היה לשלוף כתובת מ-coverageFile.paths, עם הסיבה; במקומה נטען העותק האחרון שהורד. שורות [FUCINI_REMOTE] רגילות מתעדות כל הורדה וכל בדיקה שהחזירה „ללא שינוי“ (304). |
FUCINI_REMOTE_002 | כתובת מ-coverageFile.paths לא נתנה תשובה מלאה בתוך 30 שניות — לרוב פרוקסי או VPN שמקבל את החיבור ואז שותק; במקומה נטען העותק האחרון שהורד. |
FUCINI_REMOTE_003 | כתובת מ-coverageFile.paths השיבה בדף HTML במקום בקובץ מעקב — ככל הנראה דף התחברות. הדף אינו נשמר במטמון ובמקומו נטען העותק האחרון שהורד; בדקו את האסימון ב-remote.headers. |
FUCINI_REMAP_002 | הוצע כלל pathRemap לנתיבים שטעינה השאירה ללא התאמה, עם מספר הנתיבים שהוא מסביר — או שלא ניתן היה להסיק כלל, או שהכלל שהוסק כבר נמצא בהגדרה ולא פתר אותם. |
FUCINI_REMAP_003 | הכלל המוצע נוסף ל-fuciniCoverage.pathRemap על ידי Apply Suggested Remap והכיסוי נטען מחדש. |
FUCINI_GITDIFF_001 | הרחבת Git אינה זמינה; כיסוי ה-diff מדולג ומוצגת ההרצה כולה. |
FUCINI_GITDIFF_002 | gitDiff.baseRef מתחיל ב--, מה שאף הפניית git אינה יכולה (git היה קורא אותו כאפשרות); כיסוי ה-diff מדולג ומוצגת ההרצה כולה. |
FUCINI_IGNORE | כמה קבצים fuciniCoverage.ignore השאיר מחוץ להרצה, ואילו. |
FUCINI_UNMEASURED_001 | הקבצים מהסוג של ההרצה ששום בדיקה לא טענה, אחד בכל שורה. |
FUCINI_UNMEASURED_002 | יותר מ-5,000 קבצים בסביבת העבודה תאמו אחת מהסיומות של ההרצה; רק 5,000 הראשונים נשקלו לרשימת הקבצים שלא נמדדו. |
FUCINI_UNMEASURED_003 | במצב count, כמה קבצים שלא נמדדו מופיעים ברשימה אך אינם נספרים: הגיעו לתקרת הקריאה (2,000 קבצים או 50 MB לטעינה). |
FUCINI_UNMEASURED_004 | לא ניתן היה לקרוא קובץ שלא נמדד; הוא מופיע ברשימה אך אינו נספר. |
FUCINI_TESTCOVERAGE | כמה קבצים פורסמו לתצוגת Test Coverage של VS Code. |
FUCINI_BADGE | התג נכתב, עם הנתיב, התווית והערך שלו. |
FUCINI_BADGE_001 | לא ניתן היה לכתוב את התג, עם הסיבה. |
FUCINI_WORKSPACE | תיקייה נוספה לסביבת העבודה או הוסרה ממנה; הכיסוי מתגלה מחדש. |
FUCINI_VARIABLES | מה החזירה כל ${command:…} בהגדרות הנתיבים, או מדוע נשארה כפי שנכתבה: הפקודה נכשלה, לא החזירה דבר שמיש, או שסביבת העבודה אינה מהימנה. |
FUCINI_WATCH | מה הצופה עושה: הנתיבים שנצפים, קובץ מוגדר שהופיע, משימה שצוינה ב-watch.reloadAfterTasks שהסתיימה (עם קוד היציאה שלה) והפעילה טעינה מחדש, או נתיב תחת files.watcherExclude שנדגם במקום זאת. |
18. פרטיות
הטלמטריה נשלטת על ידי ההגדרה telemetry.enabled בהיקף window. כברירת מחדל היא כבויה. הסיכום היומי והודעת ההסרה דורשים גם ש-telemetry.telemetryLevel הגלובלי של VS Code יתיר טלמטריה; איתות ההתקנה וכמה אירועים קטנים נשלחים בכל מקרה, וכך גם הרשומה בפנקס השימוש של התקנה הנמצאת בתקופת הניסיון או ברמת Community החינמית. ב-Community, Unlock Full Features נותן, בתמורה לטלמטריה הזו, את כל תכונות Pro, כולל MC/DC, למשך 30 יום, פעם אחת לכל מכונה — כבו אותה שוב ותחול מערכת התכונות הרגילה של Community; רישיון בתשלום אינו מושפע בשני המקרים. ראו את מדיניות הפרטיות לפירוט מה נשלח.
שני דברים כדאי לדעת, מפני שאפשר לפעול לפיהם. הראשון הוא מזהה פנקס השימוש שלכם: בתקופת הניסיון וב-Community ההרחבה מציגה אותו תחת Show License / Activation ובתחתית What Community Includes, ושם בחירת השורה מעתיקה אותו ופותחת את המדיניות. הפנקס מכיר את המכונה שלכם לפי גיבוב ולא לפי שום דבר אחר, ולכן המזהה הזה הוא הדרך היחידה לשאול מה שמור בו עליכם, לבקש את מחיקתו או להתנגד לו — ציינו אותו ונוכל למצוא את השורה שלכם; בלעדיו לא נוכל. השני הוא רישום ההתקנה: שורה אחת שנכתבת בפעם הראשונה שהתקנה מדווחת ונשמרת במקום להימחק לאחר 90 יום, והיא כוללת את מזהה ההתקנה, את היום, את המקום שאליו שויכה הכתובת שלה, את הגרסאות ואת מערכת ההפעלה — לא את הכתובת עצמה, ולא דבר על הקוד שלכם. הודות לו אנו יכולים לומר כמה התקנות היו לאורך השנים. שניהם מתוארים במלואם במדיניות הפרטיות, ושניהם נמחקים אם תבקשו.

19. הערכה והפעלה
Fucini Coverage Studio מופץ כגרסת קדם-שחרור להערכה. בהרצה הראשונה תתבקשו להסכים להעריך אותה, ותקופת הניסיון מתחילה — כל התכונות זמינות במהלך תקופת ניסיון של 14 ימים, מהשימוש הראשון בהתקנה הזו. אין תאריך קבוע שאחריו משהו נפסק.
החל מגרסה 2.2026.2 תקופת הניסיון של התקנה חדשה מתחילה ברגע שההרחבה הגיעה פעם אחת לשרת הרישיונות; עד אז היא פועלת ברמת Community ואומרת זאת. בקונטיינר פיתוח או ב-Codespace לא מתחילה תקופת ניסיון — קוד מנוי, מפתח או הכרטיס ל-7 ימים פותחים שם את הסט המלא.
כשתקופת הניסיון מסתיימת דבר אינו ננעל: ההרחבה עוברת לרמת Community החינמית. כדי לקבל בחזרה את המערכת המלאה, הפעילו — ההפעלה מתחברת לשרת הרישיונות ומחילה את המפתח שמתקבל אוטומטית, בלי דוא"ל ובלי מפתח להעתיק ידנית:
Screenshot pending — add assets/img/licence-dialog.png (see SCREENSHOTS.md).- הריצו
Fucini Coverage: Show License / Activation(נגיש גם משורת המצב לאחר שתקופת הניסיון או המפתח פגו) ולחצו על Request License… (או Request Renewed Key… אם הפעלתם בעבר). - אשרו את הבקשה. המפתח מונפק אוטומטית, ופרטי הקשר שלכם מבקשה קודמת נעשים בהם שימוש חוזר במקום להתבקש שוב.
- זה הכול. מפתח ההפעלה נוצר ונכתב אוטומטית אל
fuciniCoverage.license.key. שורת המצב עוברת תוך רגע מתקופת הניסיון לרישיון פעיל.
הדרך הידנית בתמונה אחת: פתחו את לוח הרישוי, בחרו Enter Key, הדביקו את המפתח מהדוא״ל — והכרזה עוברת ל־Activated.
Screenshot pending — add assets/img/activate-key.gif (see SCREENSHOTS.md).אם הבקשה האוטומטית נכשלת אי פעם (אין חיבור, תקלת שרת): הריצו Fucini Coverage: Copy Activation Request Code, שלחו אותו דרך עמוד יצירת הקשר או אל info@fucini.consulting, והדביקו את מפתח ה-FCK1.… שתקבלו בחזרה באמצעות Fucini Coverage: Enter Activation Key (או ישירות אל settings.json):
{ "fuciniCoverage.license.key": "FCK1.…הדביקו כאן את המפתח המלא…" }שם ההגדרה הוא fuciniCoverage.license.key (היקף משתמש/גלובלי). המפתח קשור למכונה שלכם ולמשתמש מערכת ההפעלה, עשוי לשאת תאריך תפוגה, ויכול לאפשר או להגביל תכונות בודדות ולהגביל טעינות כיסוי ליום. אם מוצגת ההודעה "invalid for this machine", בקשו מפתח חדש מהתקנה זו — מפתח שהונפק למכונה אחרת לעולם לא יאומת כאן.
ב-Visual Studio. במהדורה הזו אין רמה חינמית: בלי מנוי, ההרחבה אינה קוראת דבר. עם מנוי, התוכנית קובעת שם את מה שהיא קובעת ב-VS Code — תכונה שהתוכנית אינה כוללת אינה זמינה, והפקודה שלה אומרת זאת במקום לרוץ. גם שם חלה מגבלת הגרסה הישנה ביותר ששרת הרישיונות עדיין תומך בה: בנייה ישנה ממנה מקבלת על כך הודעה פעם ביום, עם התאריך שבו תפסיק לפעול, וממשיכה לעבוד עד אז. עבודה במצב לא מקוון לעולם אינה גורמת לבנייה להפסיק לעבוד.
שכבת Community החינמית: מכסה שבועית
Community אף פעם לא מפסיקה להציג כיסוי. השוליים, סרגל הסקירה, חלוניות הריחוף, CodeLens, תצוגת Coverage, מצב המעקב, כיסוי ה-diff וההיסטוריה אינם נספרים כלל, וטעינת tracefile באמצעות פקודה מוגבלת רק ל-25 ביום. מה שנמדד הוא הפלט: חמש פעמים בשבוע לכל אחת מהפעולות הבאות — פתיחת דוח ה-HTML, ייצוא, השוואה בין שתי הרצות, בדיקת הספים והצגת המקור המוער במקום.
השבוע הוא שלך, לא של לוח השנה: הוא מתחיל בשימוש הראשון ומסתיים שבעה ימים לאחר מכן. כשמכסה מנוצלת עד תום, ההודעה מציינת את הפעולה ואת היום שבו היא חוזרת, ולאחר אותה הודעה אחת רק שורת המצב מזכירה זאת. הפקודה Fucini Coverage: What Community Includes מפרטת כל מכסה, כמה ממנה נוצל ומתי היא מתאפסת — עוד לפני שמגיעים לאחת מהן.
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).שלושה פרטים שייכים לתוכניות בתשלום, בעוד שהממצאים עצמם נשארים חינמיים: Community מסמנת כל שורה שיש בה מוטנטים ששרדו ומציינת כמה, אך לא מה כל מוטנט שינה; היא מציינת כמה בדיקות הריצו שורה, אך לא את שמותיהן; והיא מציגה את Max CRAP של הרצה, אך לא את הרשימה המדורגת Riskiest Methods.
Screenshot pending — add assets/img/mutant-hover-community.png (see SCREENSHOTS.md).אם כבר השתמשת ב-Community כשהמכסה השבועית הגיעה (0.2026.83), המגבלות הקודמות שלך נשארות בתוקף למשך 30 יום; תקבל על כך הודעה פעם אחת, כולל התאריך. המונים נשמרים במחשב שלך — באחסון של VS Code עצמו וב-~/.fucini-coverage/, כך שפרופיל חדש של VS Code ממשיך את אותו שבוע — ואינם נשלחים לשום מקום.
הכרטיס ל-7 ימים
עדיין לא בשלים למינוי? כרטיס ל-7 ימים הוא כל מה שיש ב-Pro למשך שבוע אחד, בתשלום חד-פעמי: שום דבר לא מתחדש ואין מה לבטל. רוכשים אותו בדף המחירים (בהודעה שמופיעה כשמגיעים למגבלה של Community יש כפתור לכך), וקוד ההפעלה מגיע בדוא״ל.
Screenshot pending — add assets/img/pricing-week-pass.png (see SCREENSHOTS.md).- הריצו את
Fucini Coverage: Enter Subscription Code— הפקודה קיימת גם במהדורת Community וגם ב-Pro. - בחרו Pro והדביקו את הקוד
FCB1-…מהדוא״ל. - זה הכול. המפתח מונפק ומוחל עבורכם, ועובד גם במצב לא מקוון. השבוע נספר ממועד התשלום, ולכן כדאי להפעיל מיד עם הרכישה. בסיומו התוסף חוזר מעצמו ל-Community וממשיך להציג כיסוי.
Screenshot pending — add assets/img/pass-step-plan.png (see SCREENSHOTS.md).
Screenshot pending — add assets/img/pass-step-code.png (see SCREENSHOTS.md).ב-Visual Studio. אותו קוד מפעיל את Fucini Coverage Studio ל-Visual Studio, 2022 ו-2026: פתחו Tools → Coverage Studio → Licence…, הדביקו את הקוד, בחרו את התוכנית שאליה הוא שייך ולחצו Activate. חלון Coverage מציג אז Activated מעל העץ; כשפותחים אותו בחץ, השורה מציגה את התאריך שעד אליו המפתח תקף וכפתור לחשבון שלכם. מחשב אחד הוא מקום אחד: הפעילו את VS Code או את Visual Studio, והעורך השני באותו מחשב יצטרף מעצמו — Visual Studio קורא את המפתח של VS Code ו-VS Code את זה של Visual Studio — כך שדבר אינו מוזן פעמיים ולא נתפס מקום שני. שניהם מחזיקים מפתח בחיים באותו אופן: Pro Plus, Business ו-Enterprise מדווחים פעמיים ביום, ומפתח Pro מחודש בשבוע שלפני פקיעתו.


מעבר למחשב חדש וניהול מושבים
מפתח קשור למחשב אחד, ולכן מחשב חדש דורש מפתח חדש — והמנוי משלם רק על מספר המחשבים שהוא מציין. שחררו את הישן בעצמכם: היכנסו אל ניהול המנוי, אתרו את המושב שאינכם משתמשים בו עוד, בחרו Free up והפעילו את המחשב החדש באותו קוד. רכישת Pro אינה שולחת לכם סיסמה — החשבון קיים, פשוט אין לו עדיין סיסמה, ולכן בפעם הראשונה השתמשו בהגדרת או איפוס סיסמה עם הכתובת שאיתה נרשמתם.
בתוכניות Business ו־Enterprise אתם מזמינים כל עמית בדוא״ל מאותו עמוד. כל אחד מקבל קוד הפעלה השייך לו בלבד, וברגע שהוא משתמש בו כתובתו מופיעה ליד המושב שלו — כשמישהו עוזב, אתם רואים איזה מושב היה שלו ומשחררים אותו לבא בתור. הזמנה תופסת מושב מרגע השליחה ופגה לאחר 14 ימים אם לא נוצלה; בטלו אותה כדי לקבל את המקום בחזרה מיד.
בדיקת גרסאות מוקדמות
עבודה חדשה מגיעה אל fucini.software לפני שהיא מגיעה ל-Marketplace, ואפשר לבקש שתוצע לכם. פתחו את תצוגת Coverage, הרחיבו את לוח הרישיון ולחצו על בדיקת גרסאות מוקדמות… — או הגדירו fuciniCoverage.update.preRelease. מאותו רגע ההרחבה בודקת כאן ערוץ גרסאות מוקדמות נפרד לצד הרגיל, ומציעה את החדשה מבין השתיים.
Screenshot pending — add assets/img/licence-prerelease.png (see SCREENSHOTS.md).גרסאות מוקדמות נבדקו, אך אלה הגרסאות שאנו בטוחים בהן פחות מכול — אתם מתנדבים למצוא את מה שפספסנו. ההצטרפות מודיעה לנו שההתקנה הזו נמצאת בערוץ, כך שנדע כמה אנשים בודקים ונוכל לומר מה השתנה; עזיבה מחזירה אתכם למסלול הרגיל במהדורה היציבה הבאה. לא תמיד יש גרסה מוקדמת, והצטרפות כשאין כזו אינה עולה דבר: ההרחבה מוצאת ערוץ ריק, אינה אומרת על כך דבר, וממשיכה להציע מהדורות יציבות עד שתפורסם אחת.
Screenshot pending — add assets/img/licence-prerelease-joined.png (see SCREENSHOTS.md).20. יצירת קשר ורישיון
שאלות, דיווחי באגים, או תנאי רישוי חלופיים — ראו את עמוד יצירת הקשר או שלחו דוא"ל אל info@fucini.consulting. מורשה תחת MIT עם תנאי ייחוס בהערות הגרסה; ראו גם Notice.
21. בשורת הפקודה
הקורא רץ גם בלי עורך: npm install -g fucini-coverage, בחינם, על Windows, Linux, WSL ו-macOS. fucini-coverage check coverage/lcov.info --lines 80 הוא השער ש-pipeline נכשל בו; summary, export, report, badge ו-compare עושים את מה שעושות פקודות העורכים באותם שמות, ו-mcp מגיש לסוכן על שרת את ששת הכלים שבסעיף שלמעלה. הוא קורא את fucini-coverage.json, קובץ ההגדרות שמהדורת Visual Studio קוראת, כך שהספים נקבעים פעם אחת. fucini-coverage help <command> מסביר כל אחת; העמוד המלא הוא fucini-coverage ב-npm.
Screenshot pending — add assets/img/cli-demo.gif (see SCREENSHOTS.md).