Skip to content
mutastic

Quickstart

This runs mutastic on samples/pricing, a small Gradle project in mutastic’s repository whose tests pass and cover every line, and still miss something. It needs the command line on your PATH.

Terminal window
git clone https://github.com/mutastic/mutastic.git
cd mutastic
mutastic run samples/pricing

mutastic reads the build, runs the tests once to see what each line is reached by, then changes the code one small way at a time and runs the tests that reach each change. One change gets past them:

Terminal window
Missed ────────────────────────────────────────────────────────────
❯ src/main/java/com/example/pricing/Pricing.java 1 missed in 1 method
✗ MISSED no test checks discount() at total == 100
┌─ src/main/java/com/example/pricing/Pricing.java:17
│
16 │ public int discount(int total) {
17 │ if (total >= 100) {
│ ^^ changed to >
18 │ return total / 10;
│
= mutant - if (total >= 100) {
+ if (total > 100) {
= note: every test calls discount() away from the boundary
inputs seen: 50, 250 (none is 100)
covered by PricingTest#bigOrdersGetTenPercentOff, PricingTest#smallOrdersPayFullPrice (all 2 covering tests still pass)
= help: test discount() with total = 100 and assert the result
// in PricingTest
@Test
void discountWithTotal100() {
assertEquals(10, new Pricing().discount(100)); // today 10 · with this mutant 0
}
check today's value is the one you intend: the test pins what the code does now
done when mutastic verify m855c8e3c samples/pricing passes
reproduce mutastic run --only=m855c8e3c samples/pricing
or ignore mutastic ignore m855c8e3c --reason="<why>" samples/pricing
Classes 0 clean | 1 with misses (1)
Mutants ✓ 6 caught · ✗ 1 missed · 2 skipped (2 equivalent) (9)
Worst at Pricing.discount() 1 ✗
Test runs 8 (21 without coverage selection)
Start at 14:39:57
Duration 1.2s (setup 679ms, coverage 189ms, mutants 362ms)
Tests 3 on JDK 17 · 4 workers
Reports build/mutastic/mutation.json · build/mutastic/mutation.html
Score 85.7% threshold 80
PASS 1 missed, above the threshold.
Next: mutastic verify <id> samples/pricing · mutastic run --only=<id> samples/pricing · mutastic explain <id> samples/pricing
  • The gap, first: no test calls discount() with exactly 100, so nothing tells >= from >.
  • The change that got through, on its line.
  • The evidence: the values your tests actually passed (50 and 250), and the tests that reach the line, which all still pass with the change in.
  • A test that would catch it, with what the code returns today (10) and with the change (0). Today’s value is what the code does, not necessarily what it should: check it’s what you mean.
  • The commands to prove a fix, to see the mutant again, or to record a decision not to test it. Each names this project, so it works as it’s copied. m855c8e3c is the mutant’s id.

Add the suggested test to samples/pricing/src/test/java/com/example/pricing/PricingTest.java:

@Test
void discountWithTotal100() {
assertEquals(10, new Pricing().discount(100));
}

Run the command the card offered as “done when”:

Terminal window
mutastic verify m855c8e3c samples/pricing
Terminal window
mutastic: m855c8e3c is caught by com.example.pricing.PricingTest#discountWithTotal100

The mutant is caught: a test now fails when >= becomes >.

Terminal window
mutastic run samples/pricing
Terminal window
Classes 1 clean (1)
Mutants ✓ 7 caught · 2 skipped (2 equivalent) (9)
Test runs 9 (28 without coverage selection)
Start at 14:40:00
Duration 977ms (setup 423ms, coverage 214ms, mutants 340ms)
Tests 4 on JDK 17 · 4 workers
Reports build/mutastic/mutation.json · build/mutastic/mutation.html
Score 100.0% ▲ 14.3 vs last run (code changed) threshold 80
PASS Every mutant was caught.

Every mutant is caught, and the score says how far it moved since the last run.