mutation testing in python
play

Mutation Testing in Python Austin Bingham @austin_bingham - PowerPoint PPT Presentation

Mutation Testing in Python Austin Bingham @austin_bingham @sixty_north 1 Sunday, October 4, 15 2 Sunday, October 4, 15 3 Sunday, October 4, 15 Mutation Testing 4 Sunday, October 4, 15 What is mutation testing? Code under test + test


  1. Mutation Testing in Python Austin Bingham @austin_bingham @sixty_north 1 Sunday, October 4, 15

  2. 2 Sunday, October 4, 15

  3. 3 Sunday, October 4, 15

  4. Mutation Testing 4 Sunday, October 4, 15

  5. What is mutation testing? Code under test + test suite Introduce single change to code under test Run test suite Ideally, all changes will result in test failures 5 Sunday, October 4, 15

  6. Basic algorithm A nested loop of mutation and testing for operator in mutation-operators: for site in operator.sites(code): operator.mutate(site) run_tests() 6 Sunday, October 4, 15

  7. What does mutation testing tell us? Killed Survived Tests properly detected the Tests failed to detect the mutant! mutation. either Tests are inadequate for detecting Incompetent defects in necessary code or Mutation produced code which is Mutated code is extraneous inherently fm awed. 7 Sunday, October 4, 15

  8. 8 Sunday, October 4, 15

  9. Goal #1: Coverage analysis Do my tests meaningfully cover my code's functionality Is a line executed ? versus Is functionality verified ? 9 Sunday, October 4, 15

  10. Goal #2: Detect unnecessary code Survivors can indicate code which is no longer necessary 10 Sunday, October 4, 15

  11. Examples of mutations • AOD - arithmetic operator deletion Replace relational operator • AOR - arithmetic operator replacement • ASR - assignment operator replacement x > 1 • BCR - break continue replacement • COD - conditional operator deletion • COI - conditional operator insertion • CRP - constant replacement • DDL - decorator deletion x < 1 • EHD - exception handler deletion • EXS - exception swallowing break / continue replacement • IHD - hiding variable deletion • IOD - overriding method deletion break • IOP - overridden method calling position change • LCR - logical connector replacement • LOD - logical operator deletion • LOR - logical operator replacement • ROR - relational operator replacement continue • SCD - super calling deletion • SCI - super calling insert • SIR - slice index remove 11 Sunday, October 4, 15

  12. Complexity #1: It takes a loooooooong time Long test suites, large code bases, and many operators can add up What to do? ‣ Parallelize as much as possible! ‣ After baselining: • only run tests on modified code • only mutate modified code ‣ Speed up test suite 12 Image credit: John Mainstone (CC BY-SA 3.0) Sunday, October 4, 15

  13. Complexity #2: Incompetence detection Some incompetent mutants are harder to detect that others "Good luck with that." Alan Turing (apocryphal) 13 Sunday, October 4, 15

  14. Complexity #3: Equivalent mutants Some mutants have no detectable differences in functionality def consume(iterator, n): """Advance the iterator n-steps ahead. If n is none, consume entirely.""" # Use functions that consume iterators at C speed. if n is None : # feed the entire iterator into a zero-length deque collections.deque(iterator, maxlen=0) else : # advance to the empty slice starting at position n next(islice(iterator, n, n), None ) 14 Sunday, October 4, 15

  15. Cosmic Ray: Mutation Testing for Python 15 Sunday, October 4, 15

  16. Cosmic Ray operates on packages Sub-packages and modules are discovered automatically find_modules.py def find_modules(name): module_names = [name] while module_names: module_name = module_names.pop() try : module = importlib.import_module(module_name) yield module if hasattr(module, '__path__'): for _, name, _ in pkgutil.iter_modules(module.__path__): module_names.append('{}.{}'.format(module_name, name)) except Exception : # pylint:disable=broad-except LOG.exception('Unable to import %s', module_name) 16 Sunday, October 4, 15

  17. Test system plugins Support for tests systems are provided by dynamically discovered modules ‣ Using OpenStack's stevedore plugin system cosmic_ray ‣ Plugins can come from external packages py.test plugins ‣ Define a TestRunner subclass and implement unittest the _run() method • Report a simple success or failure along with a my_package printable object containing more information my_test_system ‣ TestRunner s are only given a "start directory" as context 17 Sunday, October 4, 15

  18. ast Standard library abstract syntax tree handling ‣ Generate AST from source code ‣ Modify copies of ASTs using ast.NodeTransformer 18 Sunday, October 4, 15

  19. Operators Operators are responsible for actual AST modi fj cation + 1 2 ‣ Operators inherit from Operator which in turn inherits from ast.NodeTransformer ‣ Operators are provided as plugins operator ‣ They have two primary jobs: - • Identify locations where a mutation can occur • Perform the mutation open request 1 2 19 Sunday, October 4, 15

  20. Example operator: Reverse unary subtraction Converts unary-sub to unary-add class ReverseUnarySub(Operator): def visit_UnaryOp(self, node): if isinstance(node.op, ast.USub): return self.visit_mutation_site(node) else : return node def mutate(self, node): node.op = ast.UAdd() return node 20 Sunday, October 4, 15

  21. Module management: overview Python provides a sophisticated system for performing module imports finders loaders sys.meta_path Responsible for Responsible for A list of finders which producing loaders populating module are queried in order when they recognize namespaces on with module names a module name import when import is executed 21 Sunday, October 4, 15

  22. Module management: Finder Cosmic Ray implements a custom finder ‣ The finder associates module names with ASTs ‣ It produces loaders for those modules which are under mutation 22 Sunday, October 4, 15

  23. Module management: Finder Cosmic Ray implements a custom finder class ASTFinder(MetaPathFinder): def __init__(self, fullname, ast): self._fullname = fullname self._ast = ast def find_spec(self, fullname, path, target= None ): if fullname == self._fullname: return ModuleSpec(fullname, ASTLoader(self._ast, fullname)) else : return None 23 Sunday, October 4, 15

  24. Module management: Loader Cosmic Ray implements a custom loader ‣ The loader compiles its AST in the namespace of a new module object 24 Sunday, October 4, 15

  25. Module management: Loader Cosmic Ray implements a custom loader class ASTLoader: def __init__(self, ast, name): self._ast = ast self._name = name def exec_module(self, mod): exec (compile(self._ast, self._name, 'exec'), mod.__dict__) 25 Sunday, October 4, 15

  26. multiprocessing Mutant isolation with multiple processes ‣ Avoid cross-mutant interference ‣ Signi fj cantly simpli fj es spawning cosmic-ray processes Process 1 Process 2 Process 3 Mutant 1 Mutant 2 Mutant 3 26 Sunday, October 4, 15

  27. pykka Actor model implementation in Python ‣ Simplify design ‣ Support concurrency 27 Sunday, October 4, 15

  28. asyncio Event loop to drive actors 28 Sunday, October 4, 15

  29. Operational overview Here's how we put all of these pieces together 1. Find test-runner to use 2. Identify modules for mutation 3. Find all of the operators to use 4. Lazily generate a sequence of mutated ASTs 5. For each mutant, run the tests 1.Each test runs in a new process 2.Each run manipulates its location sys.meta_path to inject the correct module 29 Sunday, October 4, 15

  30. Demo 30 Sunday, October 4, 15

  31. Up to a two line subtitle, generally used to describe the takeaway for the slide 31 Sunday, October 4, 15

  32. Thank you! Austin Bingham @austin_bingham @sixty_north 32 Sunday, October 4, 15

Download Presentation
Download Policy: The content available on the website is offered to you 'AS IS' for your personal information and use only. It cannot be commercialized, licensed, or distributed on other websites without prior consent from the author. To download a presentation, simply click this link. If you encounter any difficulties during the download process, it's possible that the publisher has removed the file from their server.

Recommend


More recommend