I'm the author of one of the tools for Java (http://pitest.org).
I have found mutation testing useful in practice, working on large legacy corporate code bases and smaller test driven projects.
I've seen a lot of dismissals of the value of mutation testing such as Bj Rollison's answer. I generally don't disagree with the points he makes, however some implicit assumptions are being made about how mutation testing can/should be used.
Mutation testing is useful (in my experience) when performed in the following ways
1. From the outset of a small/medium project.
In this scenario mutation testing supports you as you code. You can realistically aim to achieve a high mutation score.
Mutation testing will highlight gaps in your test suite (examples I keep seeing are interaction focused tests that don't check that methods actually return the value they're meant to calculate, unchecked boundaries, and lots
of instances where the TDD process you claim to be following clearly wasn't followed as you can take methods calls out without a test failing).
A surviving mutation will result in you doing one of three things
a) Writing a new test
b) Deleting some code
c) Rewriting some code
Often the outcome is b) or c).
b) is self explanatory - you have some useless code that can be removed, c) is less obvious and relates to equivalent mutations. I've found that often code that can be mutated to an equilvaent mutation can be better expressed by code that can't be mutated to an equivalent mutation. The result is usually easier to understand and maintain.
Some equivalment mutations will always remain however - usually these are from performance concerns within the code.
The definition of what constitutes a small/medium project is a little tricky to tie down - but basically small enough that the analysis completes in a time low enough to be acceptable as part of you coding feedback loop. Fortunately mutation testing tools have improved their performance by orders of in recent years. (see http://pitest.org/java_mutation_testing_systems/ for some discussion of why/how).
2. To support new development within an existing large code base
The same as above but the analysis is limited to new code. It can be useful both while developing, and part of pair review etc. It finds test suite gaps, but can also generate some useful discussion about the code.
3. To support changes to existing code within an existing larger code base
In this scenario a slice of a codebase of interest is picked out for analysis - often to support a refactoring.
As before you might end up adding tests, but probably wouldn't bother deleting or rewriting code as it is likely to be replaced anyway. Once all the surviving mutations have been investigated you have however gained an accurate
understanding of the risk involved in refactoring.
They way most people seem to assume that mutation testing should be used is ..
4. Try and achieve a 100%/85%/75% etc mutation score for an existing project
I've never tried this, and wouldn't expect it to deliver much value.
If the code base is large analysis times will be long, and the number of surviving mutations likely to be high. Trying to assess each one would be prohibitively time consuming (javalanche is meant to provide some help in this space - I've not tried it myself
though, and gather it comes with a high performance cost).
Mutation testing could perhaps still be used to assess the overall quality of and existing suite. A random sample of surviving mutation could be taken and each assesed to see if it equivalent - this could then be used to determine the likely number of surviving mutations
that repesent test suite deficiencies. This is not something I have tried myself however.
foo()
that calls methodbar()
on objectX
, if a certain condition has been satisfied. In the test, we check with interaction on mock of objectX
happened when condition has been satisfied, but we do not check whether there was no such interaction when condition was not satisfied. A mutant removes (or reverse condition in) "if" statement, while tests are still green. This suggests two options to follow: (a) either "if" statement is unnecessary or (b) a new test checking lack of interaction can be added.