muharmutation harness
Pages

Comparison

muhar is not a replacement for a mutation-testing framework. The established tools generate mutants automatically across a whole codebase and report a mutation score; muhar runs a short list of hand-written mutants and proves each one. Most projects that want broad mutation coverage should use the framework for their language. muhar fits next to it, or on its own where the guards matter more than the score.

The descriptions of other tools below are summaries of their public documentation as of October 2026. Check each tool's own documentation for current behaviour.

At a glance

ToolLanguagesMutantsTest selectionStatuses beyond caught and missed
muharAny text the suite readsHand-written, exact text editsWhole suite per mutantCOULD_NOT_MUTATE; run-level HARNESS BROKEN
GremlinsGoGenerated by operatorCoverage-basednot covered, timed out, not viable
go-mutestingGoGenerated by mutatorConfigurable through an exec scriptskipped
StrykerJavaScript, TypeScript, C#, ScalaGenerated, as mutant schemataPer-test coverageno coverage, timeout, compile error, runtime error, ignored
PITJVM languagesGenerated, on bytecodeCoverage-guided per mutantno coverage, timed out, memory error, run error, non-viable
mutmutPythonGeneratedPer-function test selectiontimeout, suspicious, skipped
cargo-mutantsRustGenerated, at function and operator levelTests of the mutated package by default, configurableunviable, timeout

What muhar does differently

  • Every mutant is a named guard. There is no generated list to triage and no score; each report line answers one question you chose.
  • Each edit is proven on disk. muhar reads the file back after writing it and reports COULD_NOT_MUTATE if the bytes are not the intended mutation (proven-landed). A mutant that never landed cannot be counted as killed or survived.
  • A broken harness cannot read as clean. A mandatory positive control must be caught before any verdict is reported. A red baseline or a missed control discards the run with exit 2 and prints no Totals: line (exit codes).
  • Language-agnostic. muhar edits text and runs a command, so the same spec format covers Go, configuration, shell and workflow files (writing good mutants).

What muhar does worse

  • No mutant generation. You write every mutant. muhar will not find the guard you forgot to list.
  • No mutation score. There is nothing to trend or threshold across a codebase.
  • No coverage-guided selection. Every mutant runs the whole suite. Planned: assay#2636.
  • No per-mutant timeout. Put the limit in the test command (timeouts).
  • Non-compiling mutants count as caught. A typo in new that breaks the build is reported CAUGHT, not unviable. Planned: assay#2639.
  • No incremental or diff mode. Every run starts from scratch. Planned: assay#2640.
  • Text report only. No HTML, no JSON output.
  • Go-specific conveniences only. The per-run build cache and go.mod rewriting help Go trees; other ecosystems get no equivalent.

Gremlins

Gremlins is a mutation-testing tool for Go. It finds candidate mutation points with Go's coverage tooling, applies its operators (arithmetic, conditionals, increments, inversions), and reports each mutant as killed, lived, not covered, timed out or not viable, with efficacy and mutant-coverage figures. Thresholds on those figures make the run exit non-zero.

Gremlins is better when you want broad, automatic coverage of a Go module, a trend figure to watch, and to skip uncovered code without running it. It also understands Go syntax, so its mutants are always well-formed.

muhar is the choice when you need a specific list of guards proven with a verdict each, a control that discards a harness that is not mutating, or mutants outside Go source.

go-mutesting

go-mutesting generates mutants of Go source with a set of mutators (branch removal, expression and statement mutators) and reports a mutation score. An exec script hook lets you control how each mutant is tested. The original repository has seen little recent maintenance; several forks continue it.

go-mutesting is better when you want generated Go mutants with a scriptable test step.

muhar is the choice when you want named, reviewed mutants, proof that each one landed, and a harness-health check before any verdict.

Stryker

Stryker covers JavaScript and TypeScript (StrykerJS), C# (Stryker.NET) and Scala (Stryker4s). It applies many mutants at once through mutant schemata, measures per-test coverage to run only the tests that reach each mutant, supports incremental runs, and produces an HTML report. It classifies mutants as killed, survived, no coverage, timeout, compile error, runtime error or ignored, and thresholds (high, low, break) control the exit status.

Stryker is better at almost everything a framework does: speed through schemata and test selection, reporting, incremental runs, and ecosystem integration for its languages.

muhar is the choice for named guards and for files outside Stryker's languages.

PIT

PIT mutates JVM bytecode, which makes it fast, and runs only the tests that cover each mutant. Its statuses are killed, survived, no coverage, timed out, memory error, run error and non-viable. It supports mutation and coverage thresholds, incremental analysis from history files, and integrates with Maven and Gradle.

PIT is better for any JVM codebase: its coverage-guided selection and bytecode mutation make whole-codebase runs practical, and its reports are mature.

muhar is the choice for a short list of guards outside the JVM, or when the evidence that each fault landed matters more than the count.

mutmut

mutmut generates mutants of Python code, runs the tests relevant to each mutated function, and keeps its state so you can browse and apply surviving mutants afterwards.

mutmut is better for Python: generated mutants, test selection, and an interactive workflow for reviewing survivors.

muhar is the choice for named guards in any language, with a run-level health check.

cargo-mutants

cargo-mutants is the closest in spirit to muhar. It generates mutants of Rust code (replacing function bodies, swapping operators), copies the tree to a scratch directory so the source is never touched, checks that the unmutated tree builds and passes first, and reports each mutant as caught, missed, unviable or timeout. Its exit status distinguishes missed mutants, timeouts and a failing baseline. It supports --shard k/n, --in-diff for changed code only, and --jobs for parallel builds.

cargo-mutants is better for Rust: generated mutants, a separate unviable status, timeouts, diff-scoped runs and a mature output directory.

muhar is the choice outside Rust, for a mandatory positive control, and for hand-chosen guards with a verdict each.

When to use which

You wantUse
A mutation score for a whole JVM, JS/TS, .NET, Scala, Python or Rust codebaseThat language's framework: PIT, Stryker, mutmut, cargo-mutants
Generated mutants across a Go moduleGremlins or a maintained go-mutesting fork
A short list of guards proven in CI, with a verdict per guardmuhar
Mutants in configuration, shell or workflow filesmuhar
BothA framework for breadth, muhar for the guards you name