SOFTWARE / SYSTEMS / AIEngineering news. Technical depth.
Architecture / 3 MIN READ

Which code is reasonable to exclude from test coverage reports?

A practical policy for excluding code from coverage reports without hiding test gaps.

Reasonable coverage exclusions are code you do not meaningfully own or cannot execute in the target runtime: generated files, branches that are provably unreachable on that platform, type-checking-only paths, and narrowly defined debug helpers. Keep recoverable error handling, fallback paths, and business rules in coverage even when they are inconvenient to test. The key rule is simple: every exclusion needs a written reason tied to execution reality or ownership, not a target percentage.

What belongs outside the coverage denominator?

Exclude code when the report would otherwise measure noise rather than test intent. Coverage.py documentation explicitly supports excluding code you “know won’t be executed” and notes built-in handling for cases like if TYPE_CHECKING: and compile-time-known branches. It also warns that excluded branches can stop counting as branches at all, which means exclusions change the denominator, not just the red highlights.

That makes a good policy narrower than “anything hard to test.” Reasonable candidates include generated client stubs, schema-derived data models, platform guards for an OS or interpreter you do not run, and dead adapter shims kept only for compatibility during a migration. In JavaScript projects using Istanbul, coverage is based on instrumented code with counters, so ignored sections directly alter what the tool reports as exercised code rather than magically proving quality in the remaining paths; see the Istanbul overview.

What should stay in coverage even if it is awkward?

Do not exclude code just because tests are expensive or setup is annoying. Retry logic, input validation, fallback behavior, error translation, and feature-flag branches are exactly where regressions hide. The same goes for except blocks that handle real failures users can trigger. If production can hit it, your tests or higher-level checks should try to hit it.

A useful test is: if this branch broke in production, would you want a test suite to catch it? If yes, keep it in scope. Defensive assertions are a gray area. Excluding an impossible-state assertion can be reasonable only if the impossibility is enforced earlier and reviewed as part of that contract. Otherwise, the assertion is part of behavior and should count.

How should teams review exclusions?

Document and review the exclusion reason in code or configuration before reviewing coverage results. Do not inspect a failing percentage and only then add ignore directives until the gate passes.

A compact checklist works well:

  • Is the code generated or outside normal team ownership?
  • Is it unreachable in this runtime by design, not by hope?
  • Would excluding it hide a user-visible failure mode?
  • Does the exclusion apply by precise pattern, not a broad regex?
  • Is there an owner and a date to revisit the assumption?

Worked example:

You have a Python package with:

  • generated OpenAPI models
  • if TYPE_CHECKING: imports
  • a __repr__ helper
  • an except ConnectionError path returning cached data

Exclude the generated directory and type-checking branch. You may exclude __repr__ if your team agrees it is debug-only and uses a narrow rule like Coverage.py’s documented exclude_also support. Do not exclude the except ConnectionError path: users can hit it, and it changes behavior.

How can you keep exclusions from going stale?

Re-review exclusions whenever platform support, code generation, or error-handling assumptions change. Coverage.py supports central exclusion patterns, but broad regexes can over-match, which the docs warn to “be careful” about. Prefer file-level ownership and small patterns over one giant ignore rule.

Follow-up: Should defensive assertions count?
Yes, unless they truly guard an unreachable state already enforced at an earlier boundary and that assumption is reviewed.

Follow-up: How can stale exclusions be found?
List excluded files and patterns in CI, require a reason comment for inline pragmas, and review any exclusion untouched for one or two release cycles.

Next step: write a one-page exclusion policy with allowed categories, one reviewer checklist, and one CI report that shows excluded lines separately from uncovered lines.

Reviewed: 2026-09-05

SOURCES & REVIEW

Sources are linked throughout this guide. Product capabilities can change; consult the linked documentation for your deployment.

Read our editorial approach ↗