Overview
Mutation testing flips the test question: instead of "does the code pass the tests?", it plants small bugs (mutants) and asks whether the tests notice. cargo-mutants is Rust's working tool — younger than Java's PIT, more active than Go's gremlins — with a design twist suited to Rust: it patches the source, so every mutant must still compile, and the type system silently kills a class of mutants other languages must test for.
Key points
- How it works: cargo-mutants enumerates mutation sites (replace a function body
with
Default::default(), swap operators, negate conditions, delete match arms…), applies each in a copy of the tree, and runs the suite. Outcomes: caught (a test failed — good), missed (suite stayed green — the finding), unviable (didn't compile — ignored). - Unviable mutants are the Rust twist: many mutations that would be live bugs in
Java/Go simply don't type-check here — the compiler is your first mutation killer;
what's left
missedis therefore concentrated signal. - Read misses as "untested behaviour", not "add an assert": a missed body-replacement means no test depends on that function's output — decide whether that's a coverage gap, dead code, or accepted risk; the tool's honesty is the value.
- Scope it or it eats CI: full runs are suite-runtime × mutant-count. Use
--in-diff(mutants only in changed code — the PR-gate mode),-f/--filefor the correctness-critical crates,--timeoutfor infinite-loop mutants, and nextest as the runner (--test-tool nextest). .cargo/mutants.tomlholds exclusions (generated code,main.rs, log lines) — curate them; a noisy mutation report gets ignored like any noisy gate.- The economics: worth running continuously on parsing/money/consensus-grade logic, occasionally elsewhere; pairs naturally with property-based tests, which tend to kill whole mutant families at once.
Examples
cargo install cargo-mutants
cargo mutants -p core --timeout 60 # one crate, bounded
cargo mutants --in-diff <(git diff main) # PR mode: only mutate the change
cargo mutants --list # preview sites without running
Related
- Testing in Rust — strategies & tooling map — parent map.
- Unit testing — the suites being judged.
- Property-based testing & fuzzing — the complementary rigor tool; properties kill mutants example tests miss.
- Mutation testing in Java — PIT, the genre's mature reference.
- Mutation testing in Go — gremlins, the same idea with younger tooling.