mutation-testing — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited mutation-testing (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Mutation testing is the behavioral signal of test-suite quality. The tool automatically modifies the production code by small, syntactically-valid changes called mutants — replace < with <=, negate a condition, flip a Boolean, alter a constant from 42 to 43, delete a statement, swap a return value for null, no-op a void method call — and runs the test suite against each modified version. If the tests fail on a mutant, the mutant is killed — the tests caught the change. If the tests still pass, the mutant survived — the tests do not actually verify the behavior at that code location, even if coverage said they reached it. The mutation score is killed / (total − equivalent mutants), where equivalent mutants are syntactic changes that produce no observable behavior difference (5-15% noise typical).
Replaces coverage-as-quality-signal with a direct behavioral verification signal. Solves the problem that high code coverage is a weak indicator of test effectiveness — Inozemtseva & Holmes (2014) showed coverage is not strongly correlated with test-suite effectiveness, which is why teams routinely ship coverage-90% codebases with bugs slipping through. Coverage asks "did the tests reach this line?"; mutation asks "would the tests catch a defect here?" — the second question is closer to what we care about, and the answer is more specific: each survived mutant is a directly addressable test-suite gap with a known location and a known kind of defect (off-by-one, condition negation, sign error, missing return assertion). Just et al. (2014) validated that mutation score correlates with real fault-detection rate, making it a meaningful proxy where coverage falls short.
Distinct from test-coverage-strategy, which owns the structural signal of which code the test suite reaches — coverage is a necessary precondition for mutation testing to apply (an uncovered mutant trivially survives because no test runs on it); coverage is the floor, mutation is the next layer. The two compose into a mature test-quality strategy: coverage as floor, mutation as verification. Distinct from test-doubles-design, which owns the construction of mocks/stubs/fakes/spies — this skill measures whether tests built with them actually verify behavior. Distinct from testing-strategy, which owns level choices (unit/integration/e2e) — mutation is a measurement applied at any level. Distinct from chaos-engineering, which is runtime fault injection into a deployed system — mutation is build-time source-code mutation. Distinct from fuzz-testing, which varies inputs to find crashes — mutation varies the program to find untested behaviors. Distinct from test-driven-development, which produces tests with high behavioral specificity as a side effect — mutation testing is one way to measure whether that specificity is actually present. Mutation testing is to a test suite what a fire drill is to a building's evacuation plan — you do not measure preparedness by counting how many exits exist (coverage), you measure it by deliberately staging a fire and watching whether anyone notices in time (mutation kill rate). An exit that nobody walks through during the drill is not really an exit, regardless of how prominently it is signposted. The wrong mental model is that the mutation score is a target to engineer toward — a number to push up the way teams push up coverage, with hard merge-gates on it. It is not. The discipline is not in maximizing the score; it is in reading the survived-mutant list. Each survivor is one of four things: (1) a real test gap — the mutant alters observable behavior and no test catches it; action: write the missing test; (2) an equivalent mutant — the syntactic change has no observable effect; action: mark as equivalent and exclude; (3) an intentional non-test — the code is intentionally unverified (defensive check, log message, debug path); action: annotate, consider whether the policy should change; (4) off-scope code — generated, vendor, scaffolding; action: exclude from analysis. Treating the score as a hard merge-gate without classifying survivors produces Goodharted tests engineered to satisfy the metric without verifying meaningful behavior, plus team frustration from equivalent-mutant noise (5-15%) being misread as real defect signal. The survival's kind (which operator caused which survivor) is part of the diagnostic, not just the count.
The behavioral test-suite quality measurement that introduces small syntactically-valid modifications (mutants) to production code and checks whether the test suite distinguishes the mutant from the original. Covers the mutant-operator vocabulary (arithmetic, relational, conditional, logical, constant, statement deletion, return value, method call removal), the kill-or-survive primitive, the mutation score metric, the equivalent-mutant problem and detection heuristics, selective mutation (Offutt et al.'s subset), execution strategies (full / incremental / bytecode / distributed), the modern tooling ecosystem (PIT, Stryker, mutmut, etc.), and the strategic distinction between mutation score as a target (anti-pattern) and the survived-mutant list as a to-do (correct use).
Mutation testing inverts the coverage question. Coverage asks: did the test reach this line? Mutation asks: would the test catch a defect at this line? The second question is closer to what we actually care about, and the answer is more specific: each survived mutant is a directly addressable test-suite gap with a known location and a known kind of defect.
The discipline is not in maximizing the score; it is in reading the survived-mutant list. Each survivor is either a real gap (the test suite does not verify this behavior — write the test), an equivalent mutant (the syntactic change has no observable effect — exclude it), or an intentional non-test (defensive check, log string, debug path — note it as intentional). Working through the list with this classification produces a stronger test suite without engineering tests to satisfy the metric.
Mutation testing's modern feasibility is what makes it strategic. A decade ago the technique was largely impractical for large codebases. Today's tools — PIT's bytecode mutation, Stryker's incremental analysis, distributed execution, test prioritization — run mutation testing in CI in minutes for codebases of hundreds of thousands of lines. The cost barrier that historically pushed teams to coverage as a substitute is largely gone.
| Operator | Example | Catches |
|---|---|---|
| Conditional Boundary | < → <= | Off-by-one in comparisons |
| Negate Conditionals | == → != | Inverted-condition bugs |
| Math | + → -, * → / | Arithmetic mistakes |
| Increments | i++ → i-- | Loop-direction bugs |
| Invert Negatives | -x → x | Sign errors |
| Return Values | return x → return null | Missing return assertions |
| Void Method Calls | obj.set(x) → (no-op) | Missing-side-effect bugs |
| Empty Returns | replace return with type's empty/default | Caught only if downstream uses the value |
| Constants | 42 → 43, true → false | Magic-number assertions |
The Offutt et al. selective subset (about 5-8 operators) captures most of the signal of the full operator set at a fraction of the cost.
| Aspect | Coverage | Mutation |
|---|---|---|
| What it measures | Did the tests execute this code? | Would the tests catch a defect here? |
| Signal direction | Floor (uncovered = unverified) | Direct measure of verification |
| Cost | Low — incremental with test execution | Higher — one test run per mutant |
| Goodhart susceptibility | High (easy to game) | Lower (harder to engineer to without writing real tests) |
| Precondition | None | Coverage at the location |
| Diagnostic output | Map of unreached lines | List of survived mutants |
A mature test-quality strategy uses coverage as the floor (reach everything important) and mutation as the verification signal (verify everything reached).
A survived mutant is not automatically a test bug. Classify each:
A test suite that addresses the real-test-gap survivors and accepts the rest will see its mutation score climb organically — and, more importantly, its real defect-detection rate.
The pattern that makes mutation testing practical in continuous integration:
--targetTests + diff-aware mode; Stryker: incremental mode).This scales to large codebases because the work per PR is bounded by the PR's size, not the codebase's size.
After applying this skill, verify:
| Instead of this skill | Use | Why |
|---|---|---|
| Measuring how much of the code the test suite reaches | test-coverage-strategy | coverage measures structural reach; this skill measures behavioral verification |
| Designing test doubles (mocks, stubs, fakes) | test-doubles-design | test-doubles owns stand-in construction; this skill measures whether the resulting tests verify behavior |
| Choosing test levels (unit/integration/e2e) | testing-strategy | testing-strategy owns the strategic level question |
| Injecting failures into a deployed system | chaos-engineering | chaos is runtime fault injection; this skill is build-time source-code mutation |
| Generating input variations to find crashes | fuzz-testing skill | fuzzing varies inputs; this skill varies the program |
| Iterating on LLM behavior via evals | eval-driven-development | eval-driven-development is the LLM analog; mutation testing is for deterministic code |
<!-- skill-graph-context:start (generated — do not edit by hand) -->
Classification
quality-assurancetruequality/testingWhen to use
how do we know the tests actually verify anything, high coverage but bugs still slip through, what is mutation testing, is the test suite good or just thorough, PIT vs StrykerNot for
Related skills
test-coverage-strategy, testing-strategyeval-driven-development, test-coverage-strategy, test-driven-development, testing-strategyConcept
Keywords
mutation testing, mutation score, mutant, mutant operator, PIT, Stryker, DeMillo, equivalent mutant, killed mutant, selective mutation<!-- skill-graph-context:end -->
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.