Coverage & Reporting
What it is
Section titled “What it is”Coverage instruments your code to count which parts executed while the tests ran. Reporting turns that raw data into something a human reads: tables, charts, CI artefacts and dashboards over time.
Run the tests │ ▼ Instrument code ──► record lines/branches/functions that ran │ ▼ Generate report ──► local HTML + CI artefact + dashboard │ ▼ Thresholds ──► pass/fail the buildCommon coverage types:
| Type | Measures | Catches |
|---|---|---|
| Line | Which lines ran | Dead code, untouched branches |
| Branch | Whether every if/else path was taken | Conditions never fully exercised |
| Function | Which functions were called | Forgotten APIs |
| Statement | Which statements ran | Similar to line |
When to use it / when to avoid it
Section titled “When to use it / when to avoid it”Use it for
- Finding regions of code no test ever touches
- CI thresholds to stop coverage sliding backwards over time
- Stakeholder reporting: trends, not just an absolute number
- Focusing on branch coverage where the code has many conditions
Avoid or reduce it when
- Chasing a 100% target as a metric (coverage only says what ran)
- Using coverage to judge quality instead of mutation testing
- Enabling coverage on every CI job, slowing the build for a report nobody reads
Frameworks & tools
Section titled “Frameworks & tools”| Tool | Ecosystem | Notes |
|---|---|---|
| Istanbul / nyc | JS/TS | The classic coverage tool, HTML/lcov output |
| c8 | JS/TS | Uses Node’s native V8 coverage, fast |
| JaCoCo | Java/JVM | Bytecode coverage; Maven/Gradle integration |
| coverage.py | Python | The Python standard; --branch for branch coverage |
| go cover | Go | Built in; go tool cover -html |
| Allure | Cross-language | Polished test reports across many languages |
| ReportPortal | Cross-language | Analytics dashboards, flaky tracking over time |
Quick setup
Section titled “Quick setup”npm install -D @vitest/coverage-v8npx vitest run --coveragepip install coverage pytest-covpytest --cov=src --cov-branch --cov-report=htmlgo test -coverprofile=cover.out ./...go tool cover -html=cover.out<!-- JaCoCo via Maven --><plugin> <groupId>org.jacoco</groupId> <artifactId>jacoco-maven-plugin</artifactId> <version>0.8.12</version> <executions> <execution> <goals><goal>prepare-agent</goal></goals> </execution> </executions></plugin>dotnet add package coverlet.collectordotnet test --collect:"XPlat Code Coverage"Example
Section titled “Example”import { defineConfig } from 'vitest/config';
export default defineConfig({ test: { coverage: { provider: 'v8', reporter: ['text', 'lcov', 'html'], thresholds: { lines: 80, branches: 70 }, }, },});[run]branch = Truesource = src
[report]fail_under = 80# Whole-module coverage totalgo test -coverprofile=cover.out ./...go tool cover -func=cover.out | tail -n 1mvn testmvn jacoco:report allure:report# open target/site/jacoco/index.htmlimport { allure } from 'allure-playwright';
test('sign in', async () => { await allure.step('open page', async () => { /* ... */ }); await allure.step('submit form', async () => { /* ... */ });});Anti-patterns & best practices
Section titled “Anti-patterns & best practices”- Set thresholds as a ratchet. Prevent regressions rather than forcing 100%.
- Prefer branch coverage in condition-heavy code; line coverage is easy to game.
- Exclude generated code from reports so the numbers mean something.
- Publish reports as CI artefacts and keep history to see trends, not snapshots.
- Coverage is not quality. A line that ran may have no assertion checking it — pair it with mutation testing.
- Have one consolidated report. Do not scatter a separate dashboard per language.
Self-assessment quiz
Section titled “Self-assessment quiz”Self-assessment quiz
Pick one answer per question, then press Check answers.