Mutation testing for Go. Discovers mutation sites, applies each one, runs your tests, and reports killed, survived, and uncovered mutations.
Run from the root of a Go module:
go run github.com/unclebob/mutate4go/cmd/mutate4go@latest path/to/file.goOr install it:
go install github.com/unclebob/mutate4go/cmd/mutate4go@latest
mutate4go path/to/file.go# Mutate-test a source file.
# If the file already has a footer manifest, this defaults to changed functions only.
mutate4go internal/foo/foo.go
# Scan a file for mutation counts without running coverage or tests
mutate4go internal/foo/foo.go --scan
# Rewrite the embedded manifest without running coverage or mutations
mutate4go internal/foo/foo.go --update-manifest
# Retest only specific lines
mutate4go internal/foo/foo.go --lines 45,67,89
# Force differential mutation explicitly
mutate4go internal/foo/foo.go --since-last-run
# Override differential behavior and mutate all covered sites
mutate4go internal/foo/foo.go --mutate-all
# Reuse existing coverage data without refreshing coverage
mutate4go internal/foo/foo.go --reuse-coverage
# Warn when a module exceeds a mutation-count threshold
mutate4go internal/foo/foo.go --mutation-warning 75
# Use a custom timeout multiplier
mutate4go internal/foo/foo.go --timeout-factor 15
# Use a custom test command
mutate4go internal/foo/foo.go --test-command "go test ./internal/foo"
# Run mutations in parallel with isolated workers
mutate4go internal/foo/foo.go --max-workers 4
# Log major actions before and after they run
mutate4go internal/foo/foo.go --verbose
# Show help
mutate4go --helpThe tool automatically:
- Runs coverage with the configured test command plus
-coverprofile=target/coverage/coverage.out - Runs a baseline test command, defaulting to
go test ./... - Applies each covered mutation, runs tests with a timeout, and restores the original file
- Runs mutations in parallel with isolated worker directories when
--max-workersis greater than1 - Writes an embedded footer manifest with the last test date and function hashes
- Defaults to differential mutation when that footer manifest already exists
- Prints a warning when mutation count exceeds
--mutation-warning(default50) - Can reuse existing coverage data with
--reuse-coverage - Can log major actions, arguments, and results to stderr with
--verbose
--scan is the fast structural mode. It skips coverage, skips test execution, and reports:
- total mutation sites
- changed mutation sites relative to the embedded manifest
- the standard mutation-count warning
--update-manifest rewrites the embedded footer manifest for the file's current contents without running coverage, baseline tests, or mutation workers.
Run mutation testing one file at a time.
go test ./...
mutate4go internal/foo/foo.go --scan
mutate4go internal/foo/foo.goRecommended loop for each file:
- Run
mutate4go path/to/file.go --max-workers 3. - If any mutations are uncovered, add or fix tests until they are covered.
- If any mutations survive, change code or tests until they are killed.
- Rerun the same single-file mutation command.
- Only start the next file when the current file has no uncovered mutations and no survivors.
For local incremental work, once a file has a footer manifest the default run is differential. You can still be explicit:
mutate4go internal/foo/foo.go --since-last-runTo force a full rerun on a file with a manifest:
mutate4go internal/foo/foo.go --mutate-all| Category | Mutations |
|---|---|
| Arithmetic | + -> -, - -> +, * -> / |
| Comparison | > <-> >=, < <-> <= |
| Equality | == <-> != |
| Boolean | true <-> false |
| Logical | && <-> ` |
| Constant | 0 <-> 1 |
mutate4go reads Go coverage profiles from:
target/coverage/coverage.outCoverage freshness is regenerated automatically unless --reuse-coverage is supplied. If a mutation site is not covered by the profile, mutate4go reports it as uncovered and does not spend time running the mutation.
The footer manifest is embedded at the end of the source file and records:
- the last successful mutation test date
- each function's id
- its line span
- a hash of its normalized source text
Differential mutation runs update the footer manifest after completion, so the next differential run compares against the latest mutation baseline.
This repo includes a Claude Code skill at skills/using-mutate4go/SKILL.md.
go test ./...
go run ./cmd/mutate4go --help
go run ./cmd/mutate4go internal/mutations/mutations.go --scanCopyright (c) Robert C. Martin. All rights reserved.