mutation testing in php with humbug

33
MUTATION TESTING IN PHP WITH HUMBUG

Upload: markredeman

Post on 21-Jan-2018

1.382 views

Category:

Software


0 download

TRANSCRIPT

Page 1: Mutation testing in php with Humbug

MUTATIONTESTINGIN PHP WITH HUMBUG

Page 2: Mutation testing in php with Humbug

@MARKREDEMANSTUDENT APPLIED MATHEMATICSFREELANCE (WEB) DEVELOPER

Page 3: Mutation testing in php with Humbug

Introduction to mutation testingHumbug, a mutation testing framework for PHP.Analyzing code coverage of open source projectsImproving your workflow with mutation testing

What's this talk about?

Page 4: Mutation testing in php with Humbug

A tool to analyze stability of a piece of codeSimilar to code coverage, but betterCan find missing tests

WHAT IS MUTATION TESTING?

Page 5: Mutation testing in php with Humbug

A quick exampleclass Customer private $orders = 0;

public function __construct($orders) $this­>orders = $orders;

public function isGoldCustomer() return $this­>orders > 10;

function testIsGoldCustomer() $this­>assertFalse((new Customer(0))­>isGoldCustomer()); // 100% line coverage :D $this­>assertTrue((new Customer(11))­>isGoldCustomer());

public function isGoldCustomer() return $this­>orders >= 10;

Page 6: Mutation testing in php with Humbug

class Customer private $orders = 0;

public function __construct($orders) $this­>orders = $orders;

public function isGoldCustomer() return $this­>orders > 10;

function testIsGoldCustomer() $this­>assertFalse((new Customer(0))­>isGoldCustomer()); // 100% line coverage :D $this­>assertFalse((new Customer(10))­>isGoldCustomer()); $this­>assertTrue((new Customer(11))­>isGoldCustomer());

Page 7: Mutation testing in php with Humbug

Generated mutants aresimilar to real faults

- Andrew, Briand, Labiche, ICSE 2005

Page 8: Mutation testing in php with Humbug

Some Definitions

Page 9: Mutation testing in php with Humbug

a piece of code that has been changed (mutated) by a mutator

killed if at least 1 test failsescaped if at all test passequivalent if there does not exist a test case which can

distinguish the mutant from the original codeuncovered mutant is not covered by a testfatal mutant produces a fatal errortimout unit tests exceed allowed timeout

Mutation

Page 10: Mutation testing in php with Humbug

Killed Mutantclass Customer private $orders = 0;

public function __construct($orders) $this­>orders = $orders;

public function isGoldCustomer() return $this­>orders < 10; // mutated ">" to "<"

function testIsGoldCustomer() $this­>assertFalse((new Customer(0))­>isGoldCustomer()); $this­>assertTrue((new Customer(11))­>isGoldCustomer());

Page 11: Mutation testing in php with Humbug

Escaped Mutantclass Customer private $orders = 0;

public function __construct($orders) $this­>orders = $orders;

public function isGoldCustomer() return $this­>orders >= 10; // mutated ">" to ">="

function testIsGoldCustomer() $this­>assertFalse((new Customer(0))­>isGoldCustomer()); $this­>assertTrue((new Customer(11))­>isGoldCustomer());

Page 12: Mutation testing in php with Humbug

Equivalent Mutantfunction sum_is_zero(array $values) $sum = 0;

foreach ($values as $value) $sum += $value;

return $sum === 0;

function sum_is_zero(array $values) $sum = 0;

foreach ($values as $value) $sum ­= $value; // mutated "+" to "­"

return $sum === 0;

Page 13: Mutation testing in php with Humbug

Increments MutatorDecrements MutatorInvert Negatives MutatorReturn Values Mutator

Math MutatorNegate MutatorConditionals BoundaryMutatorRemove ConditionalsValues Mutator

MUTATOROperator that changes (mutates) a piece of code

Page 14: Mutation testing in php with Humbug

Original Mutated+ ­­ +* // *% *

MATH MUTATORS

Page 15: Mutation testing in php with Humbug

Original Mutated== !=!= ==<= >>= << >=> <=

CONDITIONAL MUTATORS

Page 16: Mutation testing in php with Humbug

::

Mutator descriptionNegate Conditionals replace condition by ! (condition)

Remove Conditionals substitute conditional with true or falseIncrements crement numeric values by 1Decrements crement numeric values by 1

Invert Negatives multiply numeric values by ­1Return Values remove return statements

Page 17: Mutation testing in php with Humbug

MetricsMutation Score Indicator (MSI):

percentage of mutants covered & killed by testsMutation Code Coverage:

percentage of mutants covered by testsCovered Code MSI:

percentage of killed mutants that were coverd by tests$vanquishedTotal = $killedCount + $timeoutCount + $errorCount;$measurableTotal = $totalCount ­ $uncoveredCount; // = $vanquishedTotal + $escapedCount

$msi = round(100 * ($vanquishedTotal / $totalCount));$coveredRate = round(100 * ($measurableTotal / $totalCount));$cc_msi = round(100 * ($vanquishedTotal / $measurableTotal));

Page 18: Mutation testing in php with Humbug

Metrics ExampleTests: 361Line Coverage: 64.86%Mutation Score Indicator (MSI): 47%Mutation Code Coverage: 67%Covered Code MSI 70%

653 Mutants were generated284 mutants were killed218 mutants were not covered by tests131 covered mutants were not detected17 fatal errors were encountered3 time outs were encountered

47% of all mutations were detected versus 65% line coverage.

Page 19: Mutation testing in php with Humbug

HUMBUGA Mutation Testing framework for PHPMeasures the real effectiveness of your test suites and assist in their improvement.

It eats Code Coverage for breakfast

Page 20: Mutation testing in php with Humbug

Git:git clone https://github.com/padraic/humbug.gitcd humbug/path/to/composer.phar installbin/humbug

Phar:wget https://padraic.github.io/humbug/downloads/humbug.pharwget https://padraic.github.io/humbug/downloads/humbug.phar.pubkeychmod +x humbug.phar

Composer:composer global require 'humbug/humbug=~1.0@dev'# And add ~/.composer/vendor/bin to your path to make it easily executableexport PATH=~/.composer/vendor/bin:$PATH

Installation

Page 21: Mutation testing in php with Humbug

Configuration$> git clone [email protected]:yourname/yourproject.git# Check if all tests are green$> phpunit$> humbug configure

_ _ _| || |_ _ _ __ | |__ _ _ __ _| __ | || | ' \| '_ \ || / _ ||_||_|\_,_|_|_|_|_.__/\_,_\__, | |___/Humbug version 1.0­dev

Humbug configuration tool.It will guide you through Humbug configuration in few seconds.

When choosing directories, you may enter each directory and press return.To exit directory selection, please leave the next answer blank and press return.

What source directories do you want to include? : srcWhat source directories do you want to include? :Any directories to exclude from within your source directories? :Single test suite timeout in seconds [10] :Where do you want to store the text log? [humbuglog.txt] :Where do you want to store the json log (if you need it)? :Generate "humbug.json.dist"? [Y]:Configuration file "humbug.json.dist" was created.

Page 22: Mutation testing in php with Humbug

Running Humbug$> humbug

_ _ _| || |_ _ _ __ | |__ _ _ __ _| __ | || | ' \| '_ \ || / _ ||_||_|\_,_|_|_|_|_.__/\_,_\__, | |___/Humbug version 1.0­dev

Humbug running test suite to generate logs and code coverage data...

97 [==========================================================] 2 secs

Humbug has completed the initial test run successfully.Tests: 97 Line Coverage: 98.27%

Humbug is analysing source files...

Mutation Testing is commencing on 19 files...(.: killed, M: escaped, S: uncovered, E: fatal error, T: timed out)

E......M.M.......MMTT.....MMS..........................M.M.. | 60 ( 9/19)M..................M....E.......MMMMS

97 mutations were generated: 77 mutants were killed 2 mutants were not covered by tests 14 covered mutants were not detected 2 fatal errors were encountered 2 time outs were encountered

Metrics: Mutation Score Indicator (MSI): 84% Mutation Code Coverage: 98% Covered Code MSI: 85%

Remember that some mutants will inevitably be harmless (i.e. false positives).

Time: 31.39 seconds Memory: 8.75MBHumbug results are being logged as TEXT to: humbuglog.txt

Page 23: Mutation testing in php with Humbug

Analyzing Humbughumbug.log.txt

2) \Humbug\Mutator\ConditionalBoundary\GreaterThanDiff on \Carbon\CarbonInterval::__construct() in /Carbon/src/Carbon/CarbonInterval.php:­­­ Original+++ New@@ @@ $specDays += $weeks > 0 ? $weeks * Carbon::DAYS_PER_WEEK : 0;­ $specDays += $days > 0 ? $days : 0;+ $specDays += $days >= 0 ? $days : 0;

$spec .= ($specDays > 0) ? $specDays.static::PERIOD_DAYS : '';

if ($hours > 0 || $minutes > 0 || $seconds > 0) $spec .= static::PERIOD_TIME_PREFIX; $spec .= $hours > 0 ? $hours.static::PERIOD_HOURS : '';

Page 24: Mutation testing in php with Humbug

humbug.log.json

"summary": "total": 26, "kills": 23, "escapes": 1, "errors": 0, "timeouts": 0, "notests": 2, "covered_score": 96, "combined_score": 88, "mutation_coverage": 92,"escaped": [ "file": "src\/BroadwayDemo\/Basket\/Basket.php", "mutator": "\\Humbug\\Mutator\\ConditionalBoundary\\GreaterThan", "class": "\\BroadwayDemo\\Basket\\Basket", "method": "productIsInBasket", "line": 101, "diff": "­­­ Original\n+++ New\n@@ @@\n \n­ return isset($this­>productCountById[ "tests": [ "BroadwayDemo\\Basket\\AddProductToBasketTest::it_adds_a_product_to_a_basket", "BroadwayDemo\\Basket\\AddProductToBasketTest::multiple_products_can_be_added_to_a_basket" "BroadwayDemo\\Basket\\AddProductToBasketTest::a_product_can_be_added_to_a_basket_multiple_times" "BroadwayDemo\\Basket\\CheckoutTest::it_checks_out_a_basket", "BroadwayDemo\\Basket\\CheckoutTest::it_cannot_checkout_a_basket_that_has_been_emptied" "BroadwayDemo\\Basket\\CheckoutTest::nothing_happens_when_checking_out_a_basket_for_a_second_time" "BroadwayDemo\\Basket\\RemoveProductFromBasketTest::it_removes_a_product_that_was_added" "BroadwayDemo\\Basket\\RemoveProductFromBasketTest::it_does_nothing_when_removing_a_product_that_is_not_in_a_basket" "BroadwayDemo\\Basket\\RemoveProductFromBasketTest::it_only_removes_one_instance_of_a_product" ], "stderr": "", "stdout": "TAP version 13"],

Page 25: Mutation testing in php with Humbug

OptionsTimeout:

humbug ­­timeout=10Restricting files:

humbug ­­file=PrimeFactor.phphumbug ­­file=*Driver.php

Incremental analysis:humbug ­­incrementalCan off significant performance boosts by caching previous results in/home/padraic/.humbug..

Page 26: Mutation testing in php with Humbug

MutatorsBinary Arithmetic

Boolean SubstitutionConditional BoundariesNegated Conditionals

IncrementsReturn Values

Literal NumbersIf Statements

Page 27: Mutation testing in php with Humbug

HUMBUG TEST RESULTS

Package LC MSI MCC CCM Executiontime

carbon/carbon 61% 95% 100% 95% 2.25msymfony/event-dispatcher

85% 54% 69% 78% 20s

hylianshield/validator 100% 75% 89% 85% 1.35mmathiasverraes/money 96% 92% 100% 92% 16.9sthephpleague/fractal 98% 84% 98% 85% 31sbroadway/broadway-demo

96% 88% 92% 86% 5s

broadway/broadway 57% 49% 56% 87% 46s

Line Coverage (LC), Mutation Score Indicator (MSI), Mutation Code Coverage (MCC), Covered Code MSI (CCM)Timout option set to 2 seconds.

Page 28: Mutation testing in php with Humbug

TDD workflow with mutation testing

Page 31: Mutation testing in php with Humbug

Concluding remarksMutation testing will improve the quality of your testsIs becoming more mainstream over the last yearsWrite small (fast) tests

Page 32: Mutation testing in php with Humbug

I have not failed. I've justfound 10,000 ways thatwon't work

- Thomas Edison

Page 33: Mutation testing in php with Humbug

Find these slides atmutation.markredeman.nl