Skip to content

Instantly share code, notes, and snippets.

@philipmuir
Last active October 28, 2019 02:21
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save philipmuir/cee61f041ca042820f14e886a6a34ba2 to your computer and use it in GitHub Desktop.
Save philipmuir/cee61f041ca042820f14e886a6a34ba2 to your computer and use it in GitHub Desktop.
Mutation testing
<?php
declare(strict_types=1);
/**
* A bank account.
* Class taken from the phpunit test suite, modified slightly
*/
class Bank
{
/**
* The bank account's balance.
*
* @var float
*/
protected $balance = 0;
/**
* Bank constructor.
* @param float $initialBalance
*/
public function __construct(float $initialBalance = 0.0)
{
$this->balance = $initialBalance;
}
/**
* Returns the bank account's balance.
*
* @return float
*/
public function getBalance()
{
return $this->balance;
}
/**
* Deposits an amount of money to the bank account.
*
* @param float $balance
*
* @throws BankAccountException
*/
public function depositMoney($balance)
{
$this->setBalance($this->getBalance() + $balance);
return $this->getBalance();
}
/**
* Withdraws an amount of money from the bank account.
*
* @param float $balance
*
* @throws BankAccountException
*/
public function withdrawMoney($balance)
{
$this->setBalance($this->getBalance() - $balance);
return $this->getBalance();
}
/**
* Sets the bank account's balance.
*
* @param float $balance
*
* @throws BankAccountException
*/
protected function setBalance($balance)
{
if ($balance >= 0) {
$this->balance = $balance;
} else {
throw new BankAccountException();
}
}
}
<?php
use Deputy\Insights\Bank;
use Deputy\Insights\BankAccountException;
use PHPUnit\Framework\TestCase;
class BankTest extends TestCase
{
public function testDefaultBankbalanceIsZero()
{
$bank = new Bank();
$this->assertEquals(0.0, $bank->getBalance());
}
public function testDepositMoneyUpdatesBankBalanceCorrectly()
{
$bank = new Bank();
$bank->depositMoney(1.1);
$this->assertEquals(1.1, $bank->getBalance());
}
public function testWithdrawMoneyGreaterThanBalanceThrowsBankAccountException()
{
$bank = new Bank(1);
$this->expectException(BankAccountException::class);
$bank->withdrawMoney(2);
}
public function testWithdrawMoneyShouldReduceBalance()
{
$amount = 10.0;
$bank = new Bank(100);
$bank->withdrawMoney($amount);
$this->assertEquals(90.0, $bank->getBalance());
}
public function testWithdrawMoneyWithFullBankBalanceShouldZeroBankAccount()
{
$amount = 10.0;
$bank = new Bank($amount);
$bank->withdrawMoney($amount);
$this->assertEquals(0.0, $bank->getBalance());
}
}
@philipmuir
Copy link
Author

infection --coverage=build/coverage

You are running Infection with Xdebug enabled.
____ ____ __ _
/ /__ / / / /() ____
/ // __ / // _ / / __/ / __ / __
/ // / / / __/ / // // / /
/ / / / /
/
// //_/ _
/_/_//_// /_/

Running initial test suite...

PHPUnit version: 6.5.14

2 [============================] < 1 sec

Generate mutants...

Processing source code files: 2/2
Creating mutated files and processes: 12/12
.: killed, M: escaped, S: uncovered, E: fatal error, T: timed out

...........M (12 / 12)

12 mutations were generated:
11 mutants were killed
0 mutants were not covered by tests
1 covered mutants were not detected
0 errors were encountered
0 time outs were encountered

Metrics:
Mutation Score Indicator (MSI): 91%
Mutation Code Coverage: 100%
Covered Code MSI: 91%

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

Time: 0s. Memory: 10.00MB

@philipmuir
Copy link
Author

philipmuir commented Jul 9, 2019

Escaped mutants:

  1. /Users/philipmuir/code/php/php-insights/src/Bank.php:72 [M] ProtectedVisibility
--- Original
+++ New
@@ @@
      *
      * @throws BankAccountException
      */
-    protected function setBalance($balance)
+    private function setBalance($balance)
     {
         if ($balance >= 0) {
             $this->balance = $balance;

Timed Out mutants:

Not Covered mutants:

@philipmuir
Copy link
Author

Remove the testWithdrawMoneyShouldZeroBankAccount test, which covers the <= case does not change the coverage percentage, but lowers the confidence in the test suite:

@philipmuir
Copy link
Author

infection --coverage=build/coverage

You are running Infection with Xdebug enabled.
____ ____ __ _
/ /__ / / / /() ____
/ // __ / // _ / / __/ / __ / __
/ // / / / __/ / // // / /
/ / / / /
/
// //_/ _
/_/_//_// /_/

Running initial test suite...

PHPUnit version: 6.5.14

2 [============================] < 1 sec

Generate mutants...

Processing source code files: 2/2
Creating mutated files and processes: 12/12
.: killed, M: escaped, S: uncovered, E: fatal error, T: timed out

........M..M (12 / 12)

12 mutations were generated:
10 mutants were killed
0 mutants were not covered by tests
2 covered mutants were not detected
0 errors were encountered
0 time outs were encountered

Metrics:
Mutation Score Indicator (MSI): 83%
Mutation Code Coverage: 100%
Covered Code MSI: 83%

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

Time: 0s. Memory: 10.00MB

@philipmuir
Copy link
Author

philipmuir commented Jul 9, 2019

Escaped mutants:

  1. /Users/philipmuir/code/php/php-insights/src/Bank.php:72 [M] ProtectedVisibility
--- Original
+++ New
@@ @@
      *
      * @throws BankAccountException
      */
-    protected function setBalance($balance)
+    private function setBalance($balance)
     {
         if ($balance >= 0) {
             $this->balance = $balance;
  1. /Users/philipmuir/code/php/php-insights/src/Bank.php:74 [M] GreaterThanOrEqualTo
--- Original
+++ New
@@ @@
      */
     protected function setBalance($balance)
     {
-        if ($balance >= 0) {
+        if ($balance > 0) {
             $this->balance = $balance;
         } else {
             throw new BankAccountException();

Timed Out mutants:

Not Covered mutants:

@philipmuir
Copy link
Author

commenting out half the unit tests, just testing happy paths, still with a high code coverage:

//    public function testDefaultBankbalanceIsZero()
//    public function testWithdrawMoneyGreaterThanBalanceThrowsBankAccountException()
infection --coverage=build/coverage
You are running Infection with Xdebug enabled.
     ____      ____          __  _
    /  _/___  / __/__  _____/ /_(_)___  ____
    / // __ \/ /_/ _ \/ ___/ __/ / __ \/ __ \
  _/ // / / / __/  __/ /__/ /_/ / /_/ / / / /
 /___/_/ /_/_/  \___/\___/\__/_/\____/_/ /_/

Running initial test suite...

PHPUnit version: 6.5.14

    1 [============================] < 1 sec

Generate mutants...

Processing source code files: 2/2
Creating mutated files and processes: 8/8
.: killed, M: escaped, S: uncovered, E: fatal error, T: timed out

MMM....M                                             (8 / 8)

8 mutations were generated:
       4 mutants were killed
       0 mutants were not covered by tests
       4 covered mutants were not detected
       0 errors were encountered
       0 time outs were encountered

Metrics:
         Mutation Score Indicator (MSI): 50%
         Mutation Code Coverage: 100%
         Covered Code MSI: 50%

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

Time: 0s. Memory: 10.00MB
Escaped mutants:
================


1) /Users/philipmuir/code/php/php-insights/src/Bank.php:22    [M] OneZeroFloat

--- Original
+++ New
@@ @@
      * Bank constructor.
      * @param float $initialBalance
      */
-    public function __construct(float $initialBalance = 0.0)
+    public function __construct(float $initialBalance = 1.0)
     {
         $this->balance = $initialBalance;
     }


2) /Users/philipmuir/code/php/php-insights/src/Bank.php:46    [M] Plus

--- Original
+++ New
@@ @@
      */
     public function depositMoney($balance)
     {
-        $this->setBalance($this->getBalance() + $balance);
+        $this->setBalance($this->getBalance() - $balance);
         return $this->getBalance();
     }
     /**


3) /Users/philipmuir/code/php/php-insights/src/Bank.php:46    [M] MethodCallRemoval

--- Original
+++ New
@@ @@
      */
     public function depositMoney($balance)
     {
-        $this->setBalance($this->getBalance() + $balance);
+        
         return $this->getBalance();
     }
     /**


4) /Users/philipmuir/code/php/php-insights/src/Bank.php:77    [M] Throw_

--- Original
+++ New
@@ @@
         if ($balance >= 0) {
             $this->balance = $balance;
         } else {
-            throw new BankAccountException();
+            new BankAccountException();
         }
     }
 }

Timed Out mutants:
==================

Not Covered mutants:
====================

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment