09 Mutation Testing - skylerto/Software-Testing GitHub Wiki

Mutation Testing

What is Mutation Testing?

  • Mutation Testing is a testing technique that focuses on measuring the adequacy of test cases
  • Mutation Testing is NOT a testing strategy like Boundary Value or Data Flow Testing. It does not outline test data selection criteria
  • Mutation Testing should be used in conjunction with traditional testing techniques, not instead of them
  • Goal:
    • Mimic (and hence test for) typical mistakes
    • Encode knowledge about specific kinds of effective tests in practice

Mutation Testing

  • Faults are introduced into the program by creating many versions of the program called mutants
  • Each mutant contains a single fault
  • Test cases are applied to the original program and to the mutant program
  • The goal is to cause the mutant program to fail, thus demonstrating the effectiveness of the test suite

Test Case Adequacy

  • A test case is adequate if it is useful in detecting faults in a program.
  • A test case can be shown to be adequate by finding at least one mutant program that generates a different output than does the original program for that test case.
  • If the original program and all mutant programs generate the same output, the test case is inadequate.

Mutant Programs

  • Mutation testing involves the creation of a set of mutant programs of the program being tested
  • Each mutant differs from the original program by one mutation
  • A mutation is a single syntactic change that is made to a program statement

Mutation Example

Mutation Operators

  • Operand Replacement Operators:
    • Replace a single operand with another operand or constant. E.g.,
      • if (5 > y) - if(x>5) - if (y > x) Replacing y by constant 5. Replacingxbyy. Replacing x and y with each other.
    • E.g., if all operators are {+,-,*,**,/} then the following expression a = b * (c - d) will generate 8 mutants:
      • 4 by replacing * - 4 by replacing -.
  • Expression Modification Operators:
    • Replace an operator or insert new operators. E.g.,
      • if(x==y)
    • if (x >= y) Replacing == by >=. - if (x == ++y) Inserting ++.
  • Statement Modification Operators:
    • Delete the else part of an if-else statement. - Delete the entire if-else statement.
    • Replace line 3 by a return statement.
  • The Mothra mutation system (A Fortran Language System for Mutation-Based Software Testing by Offutt et al. 1987) for FORTRAN77 supports 22 mutation operators
    • Absolute value insertion
    • Constant for array reference replacement - GOTO label replacement
    • Statement deletion
    • Unary operator insertion
    • Logical connector replacement

Why Does Mutation Testing Work?

  • The operators are limited to simple single syntactic changes on the basis of the competent programmer hypothesis
  • The Competent Programmer Hypothesis
    • Programmers are generally very competent and do not create “random” programs.
    • For a given problem, a programmer, if mistaken, will create a program that is very close to a correct program.
    • An incorrect program can be created from a correct program by making some minor change to the correct program.

Mutation Testing Costs

  • The FORTRAN 77 version of the max() program generated 44 mutants using Mothra.
  • Most efforts on mutation testing have focused on reducing its cost by reducing the number of mutants while maintaining the effectiveness of the technique.

Mutation Testing Algorithm

  • Generate program test cases
  • Run each test case against the original program
    • If the output is incorrect, the program must be modified and re- tested
    • If the output is correct go to the next step ...
  • Construct mutants using a mutation testing tool
  • Execute each test case against each alive mutant
    • If the output of the mutant differs from the output of the original program, the mutant is considered incorrect and is killed - “Good test cases kill the mutants"
    • Once we find a test case that kills a mutant, we can forget the mutant and keep the test case. The mutant is dead
  • Two kinds of mutants survive:
    • Functionally equivalent to the original program: Cannot be killed
    • Killable: Test cases are insufficient to kill the mutant. New test cases must be created.

Mutation Example

Some mutants can be uninteresting

  • Three kinds of mutants are uninteresting: - Stillborn: such mutants cannot compile (or immediately crash)
    • Trivial: killed by almost any test case;
    • Equivalent: indistinguishable from original program

Mutation Example

Mutation Example

Mutation Coverage Criteria

  • Mutation Coverage (MC)
    • For each mutant m, test requirements (TR) contain a requirement to “kill m”
      • Mutation score is the percentage of mutants killed
  • The mutation score for a set of test cases is the percentage of non-equivalent mutants killed by the test data
    • Mutation Score = 100 * D / (N - E) - D: Dead mutants
      • N: Number of mutants
      • E: Number of equivalent mutants
    • A set of test cases is mutation adequate if its mutation score is 100%.

Strong and weak mutation

  • Strong mutation: a fault must be reachable, infect the state, and propagate to output
  • Weak mutation: a fault which kills a mutant need only be reachable and infect the state
  • Experiments show that weak and strong mutation require almost the same number of test cases to satisfy them

Strong mutation coverage (SMC)

  • Strongly killing mutants
    • Given a mutant m for a program P and a test case t, t is said to strongly kill m iff the output of t on P is different from the output of t on m
  • Strong mutation coverage (SMC)
    • For each mutant m in M, the test requirements (TR) contains a test case which strongly kills m

Weak mutation coverage

  • Weakly killing mutants
    • Given a mutant m that modifies a source location L in program P and a test case t, t is said to weakly kill m iff the state of the execution of P on t is different from the state of the execution of m on t, immediately after some execution of L
  • Weak mutation coverage (WMC)
    • For each mutant m in M, TR contains a test case which weakly kills m

Mutation Example

Evaluation

  • Theoretical and experimental results have shown that mutation testing is an effective approach to measuring the adequacy of test cases.
  • The major drawback of mutation testing is the cost of generating the mutants and executing each test case against them.

PIT Mutation Testing Tool

PIT Testing Tool

  • Conditionals Boundary Mutator
  • Negate Conditionals Mutator
  • Remove Conditionals Mutator
  • Math Mutator
  • Increments Mutator
  • Invert Negatives Mutator
  • Inline Constant Mutator
  • Return Values Mutator
  • Void Method Calls Mutator
  • Non Void Method Calls Mutator
  • Constructor Calls Mutator
  • Experimental Inline Constant Mutator
  • Experimental Member Variable Mutator
  • Experimental Switch Mutator