Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Mutation Testing

Mutation Testing

Brown Bag lightning talk

Avatar for Chris Sinjakli

Chris Sinjakli

May 31, 2012
Tweet

More Decks by Chris Sinjakli

Other Decks in Programming

Transcript

  1. Code coverage is a start But it can give a

    “good” score with really dreadful tests
  2. Really dreadful tests public int addTwoNumbers(int a, int b) {

    return a – b; } ... @Test public void shouldAddTwoNumbers() { int result = addTwoNumbers(1, 1); assertTrue(true); } Coverage: 100% Usefulness: 0
  3. If you can change the code, and a test doesn’t

    fail, either the code is never run or the tests are wrong.
  4. Going with our previous example public int addTwoNumbers(int a, int

    b) { return a – b; } ... @Test public void shouldAddTwoNumbers() { int result = addTwoNumbers(1, 1); assertTrue(true); } Let’s change something
  5. Going with our previous example public int addTwoNumbers(int a, int

    b) { return a + b; } ... @Test public void shouldAddTwoNumbers() { int result = addTwoNumbers(1, 1); assertTrue(true); } This still passes
  6. Slightly less obvious (and I mean slightly) public int checkConditions(boolean

    a, boolean b) { if (a && b) { return 42; } else { return 0; } } @Test public void testBothFalse() { int result = checkConditions(false, false); assertEquals(0, result); } @Test public void testBothTrue () { int result = checkConditions(true, true); assertEquals(42, result); } Coverage: 100% Usefulness: >0 But still wrong
  7. Slightly less obvious (and I mean slightly) public int checkConditions(boolean

    a, boolean b) { if (a && b) { return 42; } else { return 0; } } @Test public void testBothFalse() { int result = checkConditions(false, false); assertEquals(0, result); } @Test public void testBothTrue () { int result = checkConditions(true, true); assertEquals(42, result); } Mutate
  8. Slightly less obvious (and I mean slightly) public int checkConditions(boolean

    a, boolean b) { if (a || b) { return 42; } else { return 0; } } @Test public void testBothFalse() { int result = checkConditions(false, false); assertEquals(0, result); } @Test public void testBothTrue () { int result = checkConditions(true, true); assertEquals(42, result); } Passing tests
  9. The downfall of mutation (Equivalent Mutants) int index = 0

    while (someCondition) { doStuff(); index++; if (index == 100) { break; } } int index = 0 while (someCondition) { doStuff(); index++; if (index >= 100) { break; } } Mutates to But the programs are equivalent, so no test will fail
  10. Java • Loads of tools to choose from • Bytecode

    vs source mutation • Will look at PIT (seems like one of the better ones)
  11. PIT - pitest.org • Works with “everything” – Command line

    – Ant – Maven • Bytecode level mutations (faster) • Very customisable – Exclude classes/packages from mutation – Choose which mutations you want – Timeouts • Makes pretty HTML reports (line/mutation coverage)
  12. Ruby • Mutant seems to be the new favourite •

    Runs in Rubinius (1.8 or 1.9 mode) • Only supports RSpec • Easy to set up rvm install rbx-head rvm use rbx-head gem install mutant • And easy to use mutate “ClassName#method_to_test” spec
  13. Summary • Seems like it could identify areas of weakness

    in our tests • At the same time, could be very noisy • Might be worth just trying it against an existing project and seeing what happens