On GitHub Actions 29 , shivammathur/setup-php@v2 installs PHP and a coverage driver (a database suite also needs a services: mysql block). The workflow needs a GitHub 29 repository, so it was not run here.
name: tests
on: [push, pull_request]
jobs:
phpunit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: shivammathur/setup-php@v2
with: { php-version: '8.5', coverage: pcov }
- run: composer install --no-progress
- run: vendor/bin/phpunit --testsuite unit --coverage-textMutation testing asks whether the tests would catch a bug. Infection 2,244 (github.com/infection/infection (https://github.com/infection/infection 2,244 ), BSD-3-Clause, 0.35.4 of 2 September 2026, PHP 8.3+) plants small bugs (mutants), such as >= becoming >, reruns the covering tests against each, and reports survivors. On the shipping rule:
vendor/bin/infection src/ShippingRule.php --threads=4 --show-mutations...
- return $subtotal->cents >= 5000 ? new Money(0) : new Money(499);
+ return $subtotal->cents > 5000 ? new Money(0) : new Money(499);
...
7 mutations were generated:
6 mutants were killed by Test Framework
1 covered mutants were not detected
Metrics:
Mutation Code Coverage: 100%
Covered Code MSI: 85%One mutant escaped: the boundary bug that 100% coverage missed. Add #[TestWith([5000, 0])] and the rerun kills 7 of 7, a Covered Code MSI (mutation score indicator) of 100%. On large code bases, mutate only changed files (--git-diff-filter=AM) and set a floor with --min-msi=80.