API Mutation Testing

Would your tests notice a bug?

Karate seeds a defect into a model of your API's behavior, or tampers the live response in flight, then replays your suite and scores which defects your assertions caught. The ones they missed come back as a ranked worklist.

To be clear about a crowded word: fuzzers mutate the request to find bugs in your API. PIT and Stryker mutate source code to grade unit tests. Karate perturbs the provider's answer to grade your tests. Black-box, no source code needed.

mutation run: policy-api suite
# 24 defects seeded into provider behavior,
# your suite replayed against each one

caught    ............... 17
survived  ...............  7

survivor "discount cap raised 500 -> 5000"
          no test would notice
survivor "renewal date off by one day"
          no test would notice
survivor "empty claims list on GET /claims"
          no test would notice

# independent score excludes assertions
# that echo the server's own answer

The Problem

High coverage, weak assertions

Green means your tests ran. Coverage means they touched the endpoint. Neither answers the question that actually bites: would your assertions notice if the behavior broke?

AI writes tests that pass

An AI-generated suite reaches high coverage fast. That is what it is optimized for: exercise the endpoint, get a green, move on.

Passing is not the same as checking

The observed failure pattern in the field: the suite hits every endpoint and asserts almost nothing. A status code here, a field-exists there.

Nobody grades the graders

Your tests grade your API. Nothing grades your tests. So a suite that would miss a real bug looks exactly like one that would catch it.

The only honest way to grade a test suite is to break things on purpose and count what it caught.

How It Works

Freeze one face, perturb the other

Your suite's expectations are frozen before anything changes, so a test cannot quietly recompute its expected value to match the tampered answer. Then the provider's behavior is perturbed, two ways.

Lane 1

Seed a defect into the behavioral model

If your provider has a rulebook, an executable model of its decision logic, Karate seeds a realistic defect into it: a threshold moves, a branch inverts, a rounding rule changes. The mutated model answers your suite. Every seeded defect is a bug that could ship.

Lane 2

Tamper the live response in flight

No rulebook? The response from your real provider or mock is tampered on the way back: a field nulled, a value shifted, an item dropped from a list. If your suite still passes, that tampering is a bug it would have missed.

Start with nothing but the suite you already run

The minimum is a suite and a base URL: the response-tamper lane needs nothing else to earn a grade. Each artifact you add widens the run. An API spec enables schema-aware mutants. A rulebook enables business-logic mutants, the ones shaped like real defects in your domain. Requirements let each survivor name the acceptance criterion it leaves undefended.

An absent artifact is a disclosed narrowing, never a refusal. The report states what the run could and could not perturb.

The Score

Echoes score zero

The obvious way to game a mutation score is to assert whatever the server said. Karate detects that, and the headline number excludes it.

The independent score

Only assertions with no detected dependence on the server's answer count.

A test that reads the response and asserts the value it just read will pass no matter what the server returns. It kills every mutant on paper and none in practice. The independent score counts only assertions whose expected values do not derive from the response being checked, so a suite of copied-from-the-response echoes scores zero, which is what it deserves.

Both numbers are reported, raw and independent, side by side. The gap between them is itself a finding: it measures how much of your suite is checking the server against the server.

What the score grades, stated plainly

The mutation score grades assertion strength: would your tests notice a change in behavior. It never grades whether your expected values are correct. A test that asserts a bug kills the mutant of that bug. That is the known limit of mutation testing everywhere it is practiced, and this page will not claim otherwise.

The Output

Survivors come back as a worklist, not a number

A score tells you there is a problem. A survivor tells you which one, in the language of your domain.

Survivor

business-logic

No test would notice the discount cap dropping

The cap moved from 500 to 5000 in the mutated model. Every scenario that touches discounts still passed. The pricing behavior your business depends on is undefended.

Survivor

response-tamper

No test would notice the claims list coming back empty

The tampered response dropped every item from the array. The suite checks the status code and the shape, so it stayed green.

Survivors are ranked, so the first thing on the list is the defect your suite is most exposed to. With requirements wired in, each survivor also names the acceptance criterion it leaves undefended, which turns a test-quality report into a risk report.

The Fault Feed

The same machine, turned around

Everything above grades your tests. Point the perturbation at a dependency instead, and it grades your service.

Your mock misbehaves on purpose

The Karate mock standing in for a dependency your service consumes starts feeding it faults: a 500 where a 200 belongs, a connection that dies mid-response, a field that arrives corrupted.

Your service's resilience gets a grade

A fault your service tolerates is a pass. A fault it mishandles, a crash, a silent corruption, a hung request, is a finding that no recorded contract could express, because contracts describe agreement and this is about disagreement.

One artifact, two jobs. The paired run proves your mock faithful when it behaves. The fault feed grades what happens when it does not.

See how Karate mocks work

Where It Fits

The third adequacy axis

Coverage, provenance, and hardening answer three different questions about the same suite. Karate measures all three.

01

Covered

You exercised it. The endpoint was called, the requirement has a test against its name.

API coverage →
02

Exercised

Honestly, not faked. The evidence is real execution, not a claim, so green that was never actually earned gets surfaced.

Trust & governance →
03

Hardened

You would notice if it broke. The axis this page is about, and the one neither coverage nor provenance can see.

The Landscape

As far as we can find, nobody else ships this

The scoped claim, from a two-sweep primary-source survey in August 2026: no shipped tool grades an API suite's assertions by perturbing provider behavior without the system's source. The near-misses are worth naming, because each one is a good tool doing a different job.

WireMock, Toxiproxy, Mountebank Inject faults into responses, but emit no score. Whether your test noticed is left entirely to you.
Pact, Microcks Score the provider's conformance to a contract, not the strength of your suite's assertions. Different measured subject.
PIT, Stryker, mutmut, Diffblue Real mutation testing, of unit tests, requiring your source and build. They cannot grade a black-box API suite.
API fuzzers Mutate the request to find bugs in your API. The word overlaps; the job does not.

Academic work on grading generated API tests exists and is different in method. The claim here is scoped to shipped tools, and we will keep it scoped.

Beside contract testing, not instead of it

The paired run measures divergence: does your mock still behave like the real provider? Mutation measures adequacy: would your suite notice if either one broke? A team serious about its API estate wants both numbers, and they come from the same suite.

See contract testing

FAQ

Common questions

What is API mutation testing?

Grading a test suite by deliberately changing the provider's behavior and counting what the suite caught. A seeded defect your assertions catch is a kill; one they miss is a survivor. It answers the question coverage cannot: would your tests notice if the behavior broke?

How is this different from fuzzing?

Fuzzing mutates the request to find bugs in your API. This perturbs the response to find weaknesses in your tests. A fuzzer grades your service; mutation testing grades your assertions.

Do you need my source code?

No. Everything happens at the API boundary. The minimum is your existing suite and a base URL. A spec, a rulebook, and requirements each widen the run, and every absence is disclosed rather than refused.

Does a high mutation score mean my tests are correct?

No. It grades assertion strength, whether your tests would notice a change, never whether your expected values are right. A test that asserts a bug kills that bug's mutant. That limit is inherent to mutation testing, and we state it.

Can it test my service against a misbehaving dependency?

Yes. The fault feed points the perturbation at the dependency your service consumes: your mock of it misbehaves on purpose, and your service's resilience gets graded. A tolerated fault is a pass, a mishandled one is a finding.

Your coverage says the tests ran.

This says they would notice if the code broke. Graded at the API boundary, without your source, from the suite you already run.