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

Mutation Testing

Mutation Testing

Brown Bag lightning talk

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