phpunit/phpcov
phpcov is a CLI frontend for php-code-coverage. It merges PHPUnit --coverage-php .cov files from parallel or split runs and generates combined reports (HTML, Clover, etc.) or exports merged data back to a .cov file.
Start by installing phpcov as a PHAR using Phive for project-local, version-pinned tooling:
phive install phpcov
./tools/phpcov --version
The two most common day-to-day tasks:
./tools/phpcov execute --clover build/coverage.xml script.php
--coverage-php output:
phpunit --coverage-php build/coverage/Foo.cov tests/FooTest
phpunit --coverage-php build/coverage/Bar.cov tests/BarTest
./tools/phpcov merge --clover build/clover.xml build/coverage
Begin by running ./tools/phpcov --help to preview available commands (merge, patch-coverage, execute), then experiment with --text or --clover output for quick inline or CI reports.
CI Coverage Aggregation:
In GitHub Actions/GitLab CI with parallel test jobs, each job exports a .cov file via phpunit --coverage-php. After all jobs finish, phpcov merge combines them into a single Clover report (e.g., for uploading to Codecov).
Example step:
./tools/phpcov merge --clover coverage.xml build/coverage-${{ matrix.job }}
Patch Coverage for PR Reviews:
Enforce uncovered changes detection in pull requests:
git diff origin/main > diff.patch
phpunit --coverage-php build/coverage.cov
./tools/phpcov patch-coverage --path-prefix "$(pwd)" build/coverage.cov diff.patch
Exits non-zero if new code lacks test coverage—ideal for pre-commit hooks or CI checks.
Script Execution Workflow:
For CI scripts (e.g., artisan db:seed --force), run with coverage in one command:
./tools/phpcov execute --clover build/seed-coverage.xml artisan db:seed
Avoids manual Xdebug toggling.
Extensibility via Subcommands:
Use --html to generate human-readable reports locally, but rely on --clover/--openclover for integration with external tools (SonarQube, Codecov, etc.). Avoid overusing --php (re-serialization)—prefers downstream tools to consume raw .cov files.
Xdebug/PCOV Dependency: phpcov consumes coverage but does not collect it—ensure Xdebug (≥3.0) or PCOV is enabled when running PHPUnit or execute. Run php -v to verify extension presence.
--path-prefix Is Essential for patch-coverage:
Mismatches between git diff paths and .cov paths cause silent failures (exit code 2). Always inspect your diff’s relative paths and align with the coverage base directory:
# Common fix in CI (GitHub Actions, etc.)
./tools/phpcov patch-coverage --path-prefix "$(pwd)" build/coverage.cov diff.patch
Version Drift in .cov Files:
If .cov files were generated with different versions of php-code-coverage (e.g., phpunit 10 vs 11), merging may silently fail or produce incorrect coverage. Pin PHAR version and PHPUnit version in CI.
No Per-File Filtering in CLI:
Unlike PHPUnit, phpcov doesn’t support --whitelist or --exclude-.... Filter files before running PHPUnit or via phpunit.xml—then use phpcov only for merging/reporting.
Patch Coverage Counts Executable Lines Only:
Uncovered if (...) { blocks or function calls in a diff will fail the check—but declare(strict_types=1); or docblocks won’t. Use --text to see which lines are missing coverage:
./tools/phpcov patch-coverage --text build/coverage.cov diff.patch
How can I help you explore Laravel packages today?