🥔 mutation testing for .NET

Green doesn’t mean good.

Mutato breeds thousands of tiny mutants into your code — a flipped >=, a swapped +, a deleted line — then reruns your suite to see which ones it lets slip past. The survivors are the tests you haven’t written yet.

Get started $dotnet tool install -g dotnet-mutato --prerelease

What’s a mutant, and why should I care?

Line coverage tells you which lines ran — not whether a test would notice if that line were wrong. Mutation testing settles it: introduce a deliberate bug, rerun the tests, and if they still pass, that mutant survived — a real gap in your suite wearing a green checkmark. Mutato does this thousands of times and hands you the receipts.

Why Mutato

Honest feedback, without the wait

A mutation tester is only useful if it’s believable and fast enough to run for real. Mutato is built for both.

🧬

Type-aware mutants

Operators are chosen against Roslyn’s semantic model, so every mutant is a plausible, compilable bug — flipped conditions, swapped arithmetic, deleted statements — never type-invalid noise.

One compile, not one per mutant

A csc wrapper weaves every mutant into a single instrumented build and flips the active one with one field write. Then it runs only the tests that cover each mutant, across a pool of warm in-process hosts.

🎯

Scores you can act on

A straight mutation score plus an HTML report that points at every survivor as an exact source diff — rendered through the standard Stryker schema viewer.

Under the hood

Four steps, one recompile

1

Mutate

During a normal build, csc-mutato rewrites your sources into one assembly carrying every mutant, selectable at runtime.

2

Cover

A single coverage pass maps which tests touch which mutant, so nothing runs a test that can’t possibly kill it.

3

Run

Warm, in-process hosts flip one mutant at a time and rerun just its covering tests — in parallel, with adaptive timeouts and crash respawn.

4

Score

Killed, survived, timed-out — tallied into a mutation score and a report that shows each survivor exactly where it hides.

In practice

Install, point it at your tests, run

Zero-config discovery finds your target and test project. Add mutato init for optional hooks, or just run it.

mutato
$ dotnet tool install -g dotnet-mutato --prerelease
$ mutato init      # discover the target/test pair, wire optional hooks
$ mutato

  baseline   1,240 tests green
  mutating  Polly.Retry.RetryHelper
  ▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇ 353 mutants

  mutation score   78.3%
  killed 276 · survived 71 · timeout 6

  survived  RetryHelper.cs:88
    - if (attempt >= maxRetries)
    + if (attempt > maxRetries)  // no test caught this

Go catch the survivors 🥔

Free & open source (MIT) · works with xUnit v3, TUnit & the Microsoft Testing Platform

$dotnet tool install -g dotnet-mutato --prerelease