Gooze vs other Go mutation testing tools
How Gooze compares with Gremlins, go-mutesting, and go-mutants, including what Gooze does not do yet.
Last verified October 2026 against Gooze v1.1.0 and each tool's own documentation (gremlins.dev, zimmski/go-mutesting, avito-tech/go-mutesting, P4suta/go-mutants). “Not documented” means we found no mention of it, not that it's impossible. Spotted a mistake? Open an issue.
In short
- Gooze keeps the same three commands (
run,report view,report merge) from a weekend project to a large monorepo. Its per-file cache re-tests only what you changed, so local TDD loops stay fast, and every run still reports a score for the whole codebase, not just the diff. Sharding, a shared OCI baseline, a TUI viewer, and editor integration come built in. - Gremlins has a built-in score threshold and a git-based diff mode, but describes itself as best for “smallish” modules and is still 0.x.
- go-mutesting is a minimal framework: write your own mutators and plug in your own test runner with
--exec, at the cost of building caching, parallelism, and reporting yourself. The avito-tech fork adds a config file, JSON/HTML reports, and ignore directives. - go-mutants is feature-rich (threshold, git-based diff mode, sharding, outcome cache, JSON/HTML) but pre-release at the time of writing.
Feature matrix
| Feature | Gooze | Gremlins | go-mutesting | go-mutesting (avito-tech) | go-mutants |
|---|---|---|---|---|---|
| Config file in the repo | Yes gooze.yaml + GOOZE_* env vars | Yes .gremlins.yaml | No flags only | Yes YAML via --config | Yes .go-mutants.toml |
| Fail the build below a score | Partly no flag yet; 3-line script gate | Yes --threshold-efficacy, --threshold-mcover | Not documented | Not documented | Yes policy.minimum_score + --strict |
| Test only changed code | Yes detected by incremental execution (content hashes); no git or base ref | Yes git diff against a ref (--diff) | Not documented | Not documented | Yes git diff against a ref (--changed) |
| Incremental cache between runs | Yes per-file, reused on any machine | Not documented | Partly manual MD5 blacklist | Partly manual MD5 blacklist | Yes per-mutant outcome cache |
| Whole-codebase score without re-running everything | Yes cached results + re-tested changed files | Partly --diff tests only changed code; otherwise a full run | No full run every time | No full run every time | Yes cached outcomes; --changed narrows to the diff |
| Split one run across CI jobs | Yes -s INDEX/TOTAL + report merge | Not documented | Not documented | Not documented | Yes --shard K/N + report merge |
| Shared baseline for CI and teammates | Yes report push/pull to any OCI registry | Not documented | Not documented | Not documented | Not documented |
| Parallel workers | Yes -p/--parallel | Yes --workers | Partly via a custom --exec script | Not documented | Not documented |
| Skip code tests never execute | Yes --coverage-profile | Yes NOT COVERED status | Not documented | Not documented | Yes uncovered status |
| Ignore code with comments | Yes //gooze:ignore, per file/func/line/mutator | Partly file regex only (--exclude-files) | Partly checksum blacklist | Yes mutator-disable-* directives | Not documented |
| Write your own mutators | Partly one small function in the gooze source; no plugin API | Partly toggle built-ins only | Yes Mutator interface + Register | Not documented | Not documented |
| Custom test runner command | No on the roadmap | Partly --integration runs the full suite | Yes --exec | Yes --exec | Yes test.command |
| Machine-readable results | Yes YAML report dir + _index.yaml | Yes JSON (-o) | Partly stdout | Yes JSON and HTML | Yes JSON (Stryker-style) and HTML |
| Interactive results viewer | Yes TUI with diffs (report view) | Not documented | Not documented | Partly static HTML report | Partly live dashboard during the run |
| Results in your editor | Yes goozels language server | Not documented | Not documented | Not documented | Not documented |
| Stable (1.x) CLI and config | Yes v1.x | No v0.x; config may change between minors | Not documented | Not documented | No pre-release |
Which one to pick
- Pick Gooze if you want one tool that stays simple as the codebase grows: fast feedback while you write tests (only changed files re-run), a whole-codebase score on every PR, and CI that scales by adding shards. Start with the Quick start.
- Pick Gremlins if you need a built-in threshold flag today, or want mutations limited to the exact lines a PR changed, and the module is small.
- Pick go-mutesting if you need a fully custom test runner or want to ship mutators outside the tool's source.
Incremental execution vs git diff
Both approaches test only what changed. They differ in how they find it and what the score means afterwards.
- Git diff (Gremlins
--diff, go-mutants--changed): compare against a base branch or commit and mutate only the changed lines. Needs git history and the right base ref, and the score describes the change, not the codebase. - Incremental execution (Gooze): hash every file and its test file, re-test only what changed since the stored reports, and reuse the rest. No git, base ref, or fetch depth needed, uncommitted edits count, and the score after a one-file change is still the score for the whole project.
The trade-off is granularity: Gooze re-tests a whole changed file, a diff mode only the changed lines.
A file is re-tested when it, its _test.go, or the mutators change. Changes elsewhere (a helper in another file, a dependency) don't invalidate it, so run with --no-cache on a schedule, for example nightly. Details: Incremental runs.
What Gooze doesn't do (yet)
A threshold flag, custom mutator plugins, and a custom test runner are not supported in v1.1.0. Workarounds and status are on the Roadmap.
FAQ
Does gooze have a config file?
Yes. gooze.yaml in the project root holds output dir, excludes, parallelism, timeouts, and the coverage profile; gooze config init generates one. Every key can also be set with a GOOZE_* environment variable or a CLI flag.
Is gooze only for large projects?
No. The workflow is the same three commands for a small project and a large monorepo: gooze run, gooze report view, and, when you shard in CI, gooze report merge. Sharding and OCI baselines are opt-in for when a codebase outgrows a single job.
Is gooze good for TDD?
Yes. Results are cached per file, so after you edit a file or its test only that file is re-tested and the rest of the report is reused. The feedback loop stays short without losing the whole-codebase score.
Can gooze fail CI when the mutation score drops below a threshold?
Not with a built-in flag yet (as of v1.1.0). gooze prints Mutation score: NN.NN% in non-interactive output, and a three-line shell step compares it to a minimum and fails the job. The GitHub Actions and GitLab CI guides include it.
Does gooze only test changed code?
Yes, by design without git. gooze detects changes through incremental execution: it hashes each file and its test file and re-tests only what changed since the stored reports, reusing results for the rest, so the score always covers the whole codebase. No base branch, commit, or git history is needed, and uncommitted edits count. Granularity is per file, not per changed line. Changes in other files don't invalidate cached results, so run --no-cache periodically.
Can I write custom mutators for gooze?
Not as plugins. gooze ships six default operators (arithmetic, comparison, logical, boolean, numbers, unary). Adding an operator means one small function in the gooze source; caching, sharding, and reporting don't change. go-mutesting supports mutators outside the tool via its Mutator interface.
How is the gooze mutation score calculated?
killed / (all mutations - error). Mutants that do not compile (error) are left out; survived, not_covered, and timeout all lower the score.
Can gooze run across several CI machines?
Yes. gooze run -s INDEX/TOTAL runs one shard per job, and gooze report merge combines them. Ready-made GitHub Actions and GitLab CI pipelines are in the docs.