|
| 1 | +--- |
| 2 | +outline: [2, 3] |
| 3 | +--- |
| 4 | + |
| 5 | +# Infection |
| 6 | + |
| 7 | +[Infection](https://infection.github.io/) — инструмент мутационного тестирования для PHP. Он вносит в исходный код мелкие правки («мутации») — заменяет `>` на `>=`, убирает вызов метода, превращает `true` в `false` — и заново прогоняет ваши тесты против каждой такой версии. Если после мутации тесты всё ещё проходят, значит они на самом деле не проверяют то поведение, которое должны бы. Покрытие по строкам такого не покажет, а мутационное тестирование — да. |
| 8 | + |
| 9 | +К Infection Testo подключается через отдельный пакет — `php-testo/bridge-infection`. Он регистрируется как расширение Infection и позволяет тому использовать Testo в качестве движка для запуска тестов. |
| 10 | + |
| 11 | +::: info Пакет |
| 12 | +`php-testo/bridge-infection` — расширение для Infection. Регистрируется автоматически через Composer. Никаких плагинов в `testo.php` добавлять не нужно. |
| 13 | +::: |
| 14 | + |
| 15 | +## Установка |
| 16 | + |
| 17 | +Поставьте Infection и пакет интеграции как dev-зависимости: |
| 18 | + |
| 19 | +```bash |
| 20 | +composer require --dev infection/infection php-testo/bridge-infection |
| 21 | +``` |
| 22 | + |
| 23 | +::: warning |
| 24 | +Если вы используете [Phar-архив Infection](https://infection.github.io/guide/installation.html#Phar), то адаптер устанавливать не нужно — он уже включён в состав Phar. |
| 25 | +::: |
| 26 | + |
| 27 | +## Конфигурация |
| 28 | + |
| 29 | +Для работы Infection требуются два отчёта от Testo: |
| 30 | + |
| 31 | +- **Coverage XML** — папка с XML-файлами в формате PHPUnit Coverage. По нему Infection понимает, какими тестами покрываются строки кода, чтобы запускать только нужный набор тестов для каждого мутанта. **Обязательно**. |
| 32 | +- **JUnit XML** — единый файл с результатами тестов. Помогает Infection быстро сопоставлять тест с файлом, в котором он лежит, чтобы эффективнее пользоваться фильтрами Testo. **Опционально**, но сильно рекомендуется. |
| 33 | + |
| 34 | +Оба отчёта Infection ищет в фиксированной структуре: |
| 35 | + |
| 36 | +``` |
| 37 | +└── <tmpDir>/ |
| 38 | + └── infection/ |
| 39 | + ├── coverage-xml/*.xml |
| 40 | + └── junit.xml |
| 41 | +``` |
| 42 | + |
| 43 | +::: danger Важный момент: |
| 44 | +`tmpDir` мы должны указать в настройках Infection а путь до `coverage-xml` — в `testo.php`. |
| 45 | +::: |
| 46 | + |
| 47 | +### infection.json |
| 48 | + |
| 49 | +В настройках Infection (обычно `infection.json`) укажите, что вы используете Testo, и настройте временную директорию: |
| 50 | + |
| 51 | +```json |
| 52 | +{ |
| 53 | + "$schema": "vendor/infection/infection/resources/schema.json", |
| 54 | + "source": { |
| 55 | + "directories": ["src"] |
| 56 | + }, |
| 57 | + "testFramework": "testo", |
| 58 | + "tmpDir": "runtime", |
| 59 | + "logs": { |
| 60 | + "text": "runtime/infection.log", |
| 61 | + "html": "runtime/infection.html" |
| 62 | + } |
| 63 | +} |
| 64 | +``` |
| 65 | + |
| 66 | +### testo.php |
| 67 | + |
| 68 | +Зарегистрируйте плагин <plugin>Codecov</plugin> с отчётом <class>\Testo\Codecov\Report\PhpUnitXmlReport</class>, указывающим на папку `<tmpDir>/infection/coverage-xml`: |
| 69 | + |
| 70 | +```php |
| 71 | +use Testo\Application\Config\ApplicationConfig; |
| 72 | +use Testo\Codecov\CodecovPlugin; |
| 73 | +use Testo\Codecov\Report\PhpUnitXmlReport; |
| 74 | + |
| 75 | +return new ApplicationConfig( |
| 76 | + src: ['src'], |
| 77 | + plugins: [ |
| 78 | + new CodecovPlugin( |
| 79 | + reports: [ |
| 80 | + new PhpUnitXmlReport(__DIR__ . '/runtime/infection/coverage-xml'), |
| 81 | + ], |
| 82 | + ), |
| 83 | + ], |
| 84 | +); |
| 85 | +``` |
| 86 | + |
| 87 | +::: info |
| 88 | +Для сбора покрытия требуется расширение PCOV или XDebug. О настройке расширений и компромиссах между ними подробно написано на странице <plugin>Codecov</plugin>. |
| 89 | +::: |
| 90 | + |
| 91 | +## Запуск |
| 92 | + |
| 93 | +```bash |
| 94 | +XDEBUG_MODE=coverage vendor/bin/infection |
| 95 | +``` |
| 96 | + |
| 97 | +Можно использовать PCOV — требования к драйверу покрытия диктует <plugin>Codecov</plugin>, а не Infection. |
| 98 | + |
| 99 | +Infection прогоняет Testo дважды: |
| 100 | + |
| 101 | +1. **Начальный прогон** — запускает все тесты против оригинального кода и параллельно собирает покрытие и JUnit-лог. Это медленная фаза: тесты идут целиком, а драйвер покрытия активен. |
| 102 | +2. **Прогон мутантов** — для каждого мутанта Infection берёт только те тесты, которые задевают изменённые строки, и запускает их. Покрытие здесь уже не собирается, поэтому каждый мутант проверяется быстро. |
| 103 | + |
| 104 | +### Переиспользование готового покрытия |
| 105 | + |
| 106 | +Если отчёт о покрытии уже сгенерирован — например, на предыдущем шаге CI — его можно подсунуть Infection вместо нового прогона Testo с помощью [флага `--coverage`](https://infection.github.io/guide/command-line-options.html#coverage): |
| 107 | + |
| 108 | +```bash |
| 109 | +vendor/bin/infection --coverage=runtime/infection |
| 110 | +``` |
| 111 | + |
| 112 | +В этом режиме Infection пропускает свой начальный прогон, а указанная директория должна содержать уже готовые отчёты. |
| 113 | + |
| 114 | +Чтобы получить эти отчёты, запустите Testo с флагами `--coverage --log-junit=<tmpDir>/infection/junit.xml` — так же, как это делает адаптер для начального прогона. Важно, чтобы структура папок и имена файлов совпадали с тем, что ожидает Infection. |
0 commit comments