0, 1, 1, 2, 3, 5, 8, 13, 21, 34 ...
function fibonacci(int $n) {
+    return ($n === 0 || $n === 1) ? $n : fibonacci($n - 1) + fibonacci($n - 2);
}
fibonacci(0); // 0<?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.3/phpunit.xsd">
    <testsuites>
        <testsuite name="default">
            <directory>tests</directory>
        </testsuite>
    </testsuites>
    <coverage pathCoverage="true">
        <include>
            <directory suffix=".php">src</directory>
        </include>
    </coverage>
</phpunit>
Line Coverage, 100%
Tested
Code, 60%
class IdGenerator
{
    public function uuid(): string
    {
        // generating logic ...
        return $id;
    }
}class UserCreator
{
    public function __construct(
        private IdGenerator $idGenerator
    ) {}
    public function create(string $name, int $age): User
    {
        // some logic ...
        return new User(
            $this->idGenerator->uuid(),
            $age,
            $name
        );
    }
}class UserCreatorTest extends TestCase
{
    public function test(): void
    {
        $userCreator = new UserCreator(
            new IdGenerator()
        );
        self::assertInstanceOf(
            User::class,
            $userCreator->create('Ivan', 33)
        );
        // .. other asserts
    }
}<phpunit>
    <!-- ... -->
    <listeners>
        <listener class="Symfony\Bridge\PhpUnit\CoverageListener" />
    </listeners>
</phpunit>/**
 * @covers App\UserCreator
 */
class UserCreatorTest extends TestCase
{
    public function test(): void
    {
        $userCreator = new UserCreator(
            new IdGenerator()
        );
        // ...
    }
}Coverage shows what code is not tested
- $a = $b + $c;
+ $a = $b - $c;| Original | Mutated | 
|---|---|
| > | >= | 
| === | !== | 
| && | || | 
| '/^test$/' | '/test$/' and '/^test/' | 
| return true; | return false; | 
| foreach ($someVar as …) | foreach ([] as …); | 
| ... | ... | 
MSI = (TotalKilledMutants / TotalMutantsCount) * 100;|                         Test # Mutation #  | 
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Result | 
|---|---|---|---|---|---|---|---|---|---|
| 1 ("+" ➝ "-") | ✅ | ✅ | ✅ | ❌ | Killed | ||||
| 2 (">" ➝ ">=") | ⏳ | ||||||||
| 3 ("==" ➝ "!=) | |||||||||
| 4 (true ➝ false) | 
|                         Test # Mutation #  | 
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Result | 
|---|---|---|---|---|---|---|---|---|---|
| 1 ("+" ➝ "-") | ✅ | ✅ | ✅ | ❌ | Killed | ||||
| 2 (">" ➝ ">=") | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | Escaped | 
| 3 ("==" ➝ "!=) | ⏳ | ||||||||
| 4 (true ➝ false) | 
|                         Test # Mutation #  | 
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Result | 
|---|---|---|---|---|---|---|---|---|---|
| 1 ("+" ➝ "-") | ✅ | ✅ | ✅ | ❌ | Killed | ||||
| 2 (">" ➝ ">=") | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | Escaped | 
| 3 ("==" ➝ "!=) | ✅ | ❌ | Killed | ||||||
| 4 (true ➝ false) | ✅ | ✅ | ❌ | 
class UserAgeFilter
{
    private const AGE_THRESHOLD = 18;
    private $ageThreshold;
    public function __construct(int $ageThreshold = self::AGE_THRESHOLD)
    {
        $this->ageThreshold = $ageThreshold;
    }
    /** @param array<int, User> $collection */
    public function __invoke(array $collection)
    {
        return array_filter(
            $collection,
            function (User $user) {
                return $user->getAge() >= $this->ageThreshold;
            }
        );
    }
}public function test_it_filters_adults(): void
{
    $users = [
        User::withAge(20),
    ];
    $filter = new UserAgeFilter();
    $filteredUsers = $filter($users);
    assertCount(1, $filteredUsers);
}
class UserAgeFilter
{
    // ...
    /** @param array<int, User> $collection */
    public function __invoke(array $collection)
    {
-        return array_filter($collection, function (User $user) {
-            return $user->getAge() >= $this->ageThreshold;
-        });
+        return $collection;
    }
}public function test_it_filters_adults(): void
{
    $users = [
        User::withAge(20),
    ];
    $filter = new UserAgeFilter();
    $filteredUsers = $filter($users);
    assertCount(1, $filteredUsers);
}
public function test_it_filters_adults(): void
{
    $users = [
+       User::withAge(15),
        User::withAge(20),
    ];
    $filter = new UserAgeFilter();
    $filteredUsers = $filter($users);
    assertCount(1, $filteredUsers);
}
class UserAgeFilter
{
    // ...
    /** @param array<int, User> $collection */
    public function __invoke(array $collection)
    {
        return array_filter(
            $collection,
            function (User $user) {
-                return $user->getAge() >= $this->ageThreshold;
+                return $user->getAge() > $this->ageThreshold;
            }
        );
    }
}public function test_it_filters_adults(): void
{
    $users = [
        User::withAge(15),
        User::withAge(20),
    ];
    $filter = new UserAgeFilter();
    $filteredUsers = $filter($users);
    assertCount(1, $filteredUsers);
}
public function test_it_filters_adults(): void
{
    $users = [
        User::withAge(15),
+       User::withAge(18),
        User::withAge(20),
    ];
    $filter = new UserAgeFilter();
    $filteredUsers = $filter($users);
-   assertCount(1, $filteredUsers);
+   assertCount(2, $filteredUsers);
}
public function deactivateInactiveUsers(): void
{
    $users = $this->userRepository->findInactiveUsers();
    foreach ($users as $user) {
        $user->deactivate();
-       $this->entityManager->persist($user);
    }
    $this->entitymanager->flush();
}- $a = $b * (-1);
+ $a = $b / (-1);- $a = $b * $c;
+ $a = $b / $c;- $result = [$a, $b] + [$c, $d];
+ $result = [$a, $b] - [$c, $d];infection --git-diff-filter=AM --git-diff-base=master|                         Test # Mutation #  | 
1 | 2 | 3 | Result | 
|---|---|---|---|---|
| 1 | ✅ 0.132s | ✅ 0.387s  | 
❌ 0.399s  | 
Killed | 
| 2 | ✅ | ✅ | ✅ | Escaped | 
| 3 | ✅ | ❌ | Killed | |
| 4 | ✅ | ✅ | ❌ | 
|                         Test # Mutation #  | 
1 | 2 | 3 | Result | 
|---|---|---|---|---|
| 1 | ❌ 0.399s  | 
✅ 0.387s  | 
✅ 0.132s | Killed | 
| 2 | ✅ | ✅ | ✅ | Escaped | 
| 3 | ❌ | ✅ | Killed | |
| 4 | ❌ | ✅ | ✅ | 
|                         Test # Mutation #  | 
1 | 2 | 3 | Result | 
|---|---|---|---|---|
| 1 | ❌ 0.399s  | 
Killed | ||
| 2 | ✅ | ✅ | ✅ | Escaped | 
| 3 | ❌ | Killed | ||
| 4 | ❌ | 
- Time: 1m 49s. Memory: 0.07GB (first run)
+ Time: 38s. Memory: 0.07GB (second run)$ infection --git-diff-filter=AM --threads=4 --show-mutations$ infection --min-covered-msi=1005) /srv/api/src/User/Status/StatusTransitioner.php:22    [M] PublicVisibility
--- Original
+++ New
@@ @@
-    public function isAllowedTransitionTo(User $user, UserStatus $toStatus) : bool
+    protected function isAllowedTransitionTo(User $user, UserStatus $toStatus) : bool
     {
         if ($user->isDraft()) {
             return $toStatus->isActive() || $toStatus->isDeleted();Supported Test Frameworks:
Supported Coverage Drivers:
Supported PHP: 7.1+