In this lesson, you will learn how to identify gaps in your test suite by intentionally injecting faults into your source code to measure your tests' effectiveness.
The Logic of Mutation Testing
Even with high code coverage, your tests might be "shallow"—they might execute the code without actually asserting the correctness of the logic. Mutation Testing addresses this by applying small, automated changes to your source code, known as mutants.
If your test suite passes despite these changes, the mutant has "survived," indicating that your tests are not sensitive enough to detect that specific logic failure. If your tests fail, the mutant is "killed," proving your tests are successfully enforcing that piece of code.
A Concrete Illustration
Consider this simple C# method:
public bool IsAdult(int age)
{
return age >= 18;
}
A mutation testing tool might generate a mutant by changing the >= operator to >. The new, mutated code looks like this:
public bool IsAdult(int age)
{
return age > 18;
}
If your test suite includes Assert.True(IsAdult(18)), the test will fail when it runs against this mutant (because 18 is not greater than 18). In this case, the test kills the mutant.
However, if your test suite only contains Assert.True(IsAdult(20)) and Assert.False(IsAdult(15)), these tests will still pass against the mutated code. Because the tests failed to detect the change, the mutant survives. This reveals a "blind spot" in your test coverage: you neglected to test the boundary condition (the number 18).
The Feedback Loop
By analyzing survival rates, you gain a "Mutation Score." A low score isn't a sign that your code is broken; it’s a high-precision metric showing exactly where your existing assertions are insufficient. Rather than just aiming for line coverage, you are now aiming for fault-detection coverage. This forces you to write more rigorous tests that verify specific behaviors rather than just exercising code paths.
Key Takeaway: Mutation testing treats your tests as the subject of the experiment, verifying that they are robust enough to fail when the underlying business logic is corrupted.