I set up PHPUnit to work with two different namespaces in a non-Laravel project, and it works perfectly. This is the folder structure of my working example:
├── docker-compose.yml
├── Dockerfile
├── composer.json
├── phpunit.xml
├── app/
│ └── Example.php
├── modules/
│ └── Example.php
└── tests/
├── AppTest.php
└── ModulesTest.php
In this setup, phpunit.xml
looks like this:
<testsuites>
<testsuite name="Tests">
<directory>tests</directory>
</testsuite>
</testsuites>
<source>
<include>
<directory>app</directory>
<directory>modules</directory>
</include>
</source>
And the namespaces are defined in composer.json
as follows:
"autoload": {
"psr-4": {
"App\\": "app/",
"Modules\\": "modules/"
}
}
I run the following command to generate the coverage report:
docker compose exec php ./vendor/bin/phpunit --coverage-html coverage-report
In this non-Laravel example, the code coverage report correctly shows both app
and modules
namespaces covered by tests.
You can checkout the full repository of my example at https://github.com/iwasherefirst2/poc-coverage
The Issue in Laravel:
When I replicate this setup in a fresh Laravel 10.48.24 project, with the same structure and configuration, the coverage report fails to include the modules folder, even though the tests for it pass successfully.
Here is the Laravel-specific information:
Both projects use the same PHPUnit version, and the tests in Laravel are plain unit tests (use PHPUnit\Framework\TestCase
). However, the coverage report for my Laravel app only includes the app namespace, completely omitting modules.
Here is also the full repository to look at https://github.com/iwasherefirst2/poc-laravel-coverage-modules
What I Tried:
Key Observations:
Question: Why does the PHPUnit code coverage report fail to include the modules namespace in Laravel, even though the tests are running and passing? Could this be related to Laravel’s PHPUnit integration or autoload configuration? How can I resolve this and ensure full coverage for both namespaces in Laravel?
After thorough investigation, I identified that the difference between the Laravel repository and the non-Laravel repository was the use of PCOV
during code coverage in the Laravel setup, while the non-Laravel repository relied on Xdebug
.
PCOV
appears to have issues handling code coverage for multiple directories at the root level. This caused the modules
directory to be excluded from the coverage report in the Laravel repository.
To resolve this issue, you can disable PCOV
and use Xdebug
.
Modify your Dockerfile to exclude PCOV
entirely. Simply remove the php8.2-pcov
package from the installation step:
RUN apt-get update && apt-get install -y \
php8.2-cli \
php8.2-xdebug \
...
# Remove php8.2-pcov or don't include it at all
If removing PCOV
is not an option, you can manually disable it during the coverage run by passing the pcov.enabled=0
directive:
sail php -d pcov.enabled=0 ./vendor/bin/phpunit --coverage-text
Ensure your phpunit.xml
file includes the appropriate configuration for code coverage, depending on your PHPUnit version.
Use the <filter>
tag with a <whitelist>
section:
<filter>
<whitelist>
<directory suffix=".php">app</directory>
<directory suffix=".php">modules</directory>
</whitelist>
</filter>
Switch to the <source>
tag with <include>
:
<source>
<include>
<directory suffix=".php">app</directory>
<directory suffix=".php">modules</directory>
</include>
</source>