principletypescriptnoneModerate
Code Coverage Traps: 100% Coverage Does Not Mean No Bugs
Viewed 0 times
code coveragemutation testingbranch coveragecoverage thresholdmeaningful tests
Problem
Teams chase 100% code coverage but have tests that cover lines without asserting behavior. High coverage gives false confidence while bugs in integration paths go undetected.
Solution
Focus on meaningful coverage metrics and mutation testing rather than line coverage alone.
// BAD: Covers the line but asserts nothing
test('formatDate exists', () => {
formatDate(new Date()); // Called but not asserted
});
// GOOD: Tests actual behavior with edge cases
test('formatDate formats correctly', () => {
expect(formatDate(new Date('2024-01-15'))).toBe('Jan 15, 2024');
expect(formatDate(new Date('2024-12-31'))).toBe('Dec 31, 2024');
});
test('formatDate handles invalid date', () => {
expect(formatDate(new Date('invalid'))).toBe('Invalid date');
});
// Coverage config: exclude non-testable files
// jest.config.js
export default {
collectCoverageFrom: [
'src/**/*.ts',
'!src/**/*.d.ts',
'!src/types/**',
'!src/**/index.ts', // re-exports only
],
coverageThreshold: {
global: { branches: 80, functions: 90 },
},
};Why
Line coverage measures which code ran, not whether it was correct. A test can execute every line while making no assertions. Branches coverage is more meaningful; mutation testing is the strongest signal.
Gotchas
- Branch coverage is more valuable than line coverage — focus on if/else, ternary, and null checks.
- Setting coverage thresholds in CI prevents regression but can incentivize meaningless tests.
- Use Stryker (mutation testing) to verify that your tests actually catch bugs.
Revisions (0)
No revisions yet.