How it works
The explanation, with examples you can run.
100% coverage that misses a bug
Take isAdult(age), implemented as age >= 18. Two tests, ages 30 and 10, run every line and both outcomes, so coverage is 100%. Now run them against a few mutants, the same kind of changes a mutation tool makes:
Press Run to see what your code prints, in order.
Runs in this browser, in an isolated frame with no access to this page. console.log, info, warn and error are shown; code runs as a classic script, so use an async function for await.
The weak suite lets age > 18 survive. It can't tell an 18-year-old from a 17-year-old, which is exactly the kind of off-by-one bug that reaches production. Two boundary tests kill it. The coverage number was 100% both times.
Reading coverage well
- Prefer branch coverage to line coverage. A one-line
a && b ? x : ycounts as covered after one run, whichever path that run took. - Look at what is uncovered and ask whether it worries you: error handling, rarely used options, the retry path. That conversation is worth more than the percentage.
- Expect thoughtful testing to land high (Fowler mentions the upper 80s or 90s), but be wary of a hard 100% gate. It rewards tests written for the number.
- Ratchet rather than gate: fail the build if coverage on changed files drops, not if the whole repo misses a target.
Mutation testing in practice
For JavaScript and TypeScript, Stryker runs your existing test command once per mutant. It changes operators, flips conditions, empties blocks and replaces return values, then reports each mutant as killed (some test failed), survived (all passed), or not covered (no test reached it). The mutation score is the share of mutants your tests detect.
npm install --save-dev @stryker-mutator/corenpx stryker init # asks about your test runner and writes a config filenpx stryker run # HTML report with each surviving mutant in placeBecause the suite runs once per mutant, a full run on a large codebase can take a long time. Scope it to the modules where a wrong answer is expensive (pricing, permissions, money) and run it nightly or on changed files. Some survivors are equivalent mutants: changes that behave the same as the original. Ignore those; the others usually point to a missing boundary test or a missing assertion.
Check yourself
3 questions. Get them all right to finish this topic.
0 of 3 right so far. Get all three to finish this topic.