3. THE DEVIL’S ADVOCATE
➢Software Gardener
addicted to open source and
code quality
➢@SonarSource Language
Team Technical Leader
@nicolas_frankel @_godin_ #mutationtesting
3
7. CODE COVERAGE
@nicolas_frankel @_godin_ #mutationtesting
“Code coverage is a
measure used to describe the
degree to which the source
code of a program is tested”
--Wikipedia
http://en.wikipedia.org/wiki/Co
de_coverage
7
9. COMPUTING CODE COVERAGE
CC =
Lexecuted
Ltotal
*100
CC: Code Coverage
(in percent)
Lexecuted: Number of
executed lines of code
Ltotal: Number of total
lines of code
@nicolas_frankel @_godin_ #mutationtesting
9
11. 100% CODE COVERAGE?
@nicolas_frankel @_godin_ #mutationtesting
“Is 100% code coverage
realistic? Of course it is. If you
can write a line of code, you
can write another that tests
it.”
Robert Martin (Uncle Bob)
https://twitter.com/unclebobma
rtin/status/5596662050966732
8
11
12. ASSERT-LESS TESTING
@Test
public void add_should_add() {
new Math().add(1, 1);
}
@nicolas_frankel @_godin_ #mutationtesting
But, where is the
assert?
As long as the Code Coverage is
OK…
12
13. CODE COVERAGE AS A MEASURE OF
TEST QUALITY
@nicolas_frankel @_godin_ #mutationtesting
Any metric can be gamed!
Code coverage is a metric…
⇒ Code coverage can be
gamed
• On purpose
• Or by accident
13
14. CODE COVERAGE AS A MEASURE OF
TEST QUALITY
@nicolas_frankel @_godin_ #mutationtesting
Code Coverage lulls you into
a false sense of security…
14
15. THE PROBLEM STILL STANDS
@nicolas_frankel @_godin_ #mutationtesting
Code coverage cannot
ensure test quality
• Is there another way?
Mutation Testing to the
rescue!
15
16. THE CAST
@nicolas_frankel @_godin_ #mutationtesting
William Stryker
Original Source Code
Jason Stryker
Modified Source Code
a.k.a “The Mutant”
16
17. public class Math {
public int add(int i1, int i2) {
return i1 + i2;
}
}
@nicolas_frankel @_godin_ #mutationtesting
public class Math {
public int add(int i1, int i2) {
return i1 - i2;
}
}
17
21. KILLED OR SURVIVING?
@nicolas_frankel @_godin_ #mutationtesting
Surviving means changing
the source code did not
change the test result
• It’s bad!
Killed means changing the
source code changed the test
result
• It’s good
21
22. TEST THE CODE
@nicolas_frankel @_godin_ #mutationtesting
public class Math {
public int add(int i1, int i2) {
return i1 + i2;
}
}
@Test
public void add_should_add() {
new Math().add(1, 1);
}
✔Execute Test
22
23. SURVIVING MUTANT
@nicolas_frankel @_godin_ #mutationtesting
public class Math {
public int add(int i1, int i2) {
return i1 - i2;
}
}
@Test
public void add_should_add() {
new Math().add(1, 1);
}
✔Execute SAME Test
23
24. TEST THE CODE
@nicolas_frankel @_godin_ #mutationtesting
public class Math {
public int add(int i1, int i2) {
return i1 + i2;
}
}
@Test
public void add_should_add() {
int sum = new Math().add(1, 1);
Assert.assertEquals(sum, 2);
}
✔Execute Test
24
25. KILLED MUTANT
@nicolas_frankel @_godin_ #mutationtesting
public class Math {
public int add(int i1, int i2) {
return i1 - i2;
}
}
@Test
public void add_should_add() {
int sum = new Math().add(1, 1);
Assert.assertEquals(sum, 2);
}
✗Execute SAME Test
25
26. MUTATION TESTING IN JAVA
@nicolas_frankel @_godin_ #mutationtesting
PIT is a tool for Mutation
testing
Available as
• Command-line tool
• Ant target
• Maven plugin
26
28. PIT MUTATORS SAMPLE
Name Example source Result
Conditionals Boundary > >=
Negate Conditionals == !=
Remove Conditionals foo == bar true
Math + -
Increments foo++ foo--
Invert Negatives -foo foo
Inline Constant static final FOO= 42 static final FOO = 43
Return Values return true return false
Void Method Call System.out.println("foo")
Non Void Method Call long t = System.currentTimeMillis() long t = 0
Constructor Call Date d = new Date() Date d = null;
@nicolas_frankel @_godin_ #mutationtesting
28
36. BENCHMARKING (KIND OF)
part of SonarSource C++
Frontend
15K source LoC
about 1K tests in 13K LoC
mvn test
11 sec
You're doing it wrong.
@nicolas_frankel @_godin_ #mutationtesting
40
38. WHY SO SLOW?
@nicolas_frankel @_godin_ #mutationtesting
Analyze test code
For each class under test
• For each mutator
• Create mutation
• For each mutation
• Run test
• Analyze result
• Aggregate results
42
48. INCREMENTAL ANALYSIS
ØSome metadata stored between runs
ØDuring each following run mutant will not be
checked again, if the last time it:
•timed out, and class has not changed
•was killed, and neither class nor test have
changed
•survived, and there are no new/changed tests
for it
@nicolas_frankel @_godin_ #mutationtesting
52
51. DO USE ON CONTINUOUS INTEGRATION
SERVERS
mvn
org.pitest:pitest-maven:mutationCoverage
-DtimestampedReports=false
@nicolas_frankel @_godin_ #mutationtesting
55
52. IS MUTATION TESTING THE SILVER
BULLET?
@nicolas_frankel @_godin_ #mutationtesting
Sorry, no!
It only
• Checks the relevance of your
unit tests
• Points out potential bugs
56
53. WHAT IT DOESN’T DO
@nicolas_frankel @_godin_ #mutationtesting
Validate the assembled
application
• Integration Testing
Check the performance
• Performance Testing
Look out for display bugs
• End-to-end testing
Etc.
57
54. TESTING IS ABOUT ROI
@nicolas_frankel @_godin_ #mutationtesting
Don’t test to achieve 100%
coverage
Test because it saves money
in the long run
Prioritize:
• Business-critical code
• Complex code
58