我将 PHPUnit 设置为在非 Laravel 项目中使用两个不同的命名空间,并且它运行得很好。这是我的工作示例的文件夹结构:
├── docker-compose.yml
├── Dockerfile
├── composer.json
├── phpunit.xml
├── app/
│ └── Example.php
├── modules/
│ └── Example.php
└── tests/
├── AppTest.php
└── ModulesTest.php
在此设置中,
phpunit.xml
看起来像这样:
<testsuites>
<testsuite name="Tests">
<directory>tests</directory>
</testsuite>
</testsuites>
<source>
<include>
<directory>app</directory>
<directory>modules</directory>
</include>
</source>
命名空间在
composer.json
中定义如下:
"autoload": {
"psr-4": {
"App\\": "app/",
"Modules\\": "modules/"
}
}
我运行以下命令来生成覆盖率报告:
docker compose exec php ./vendor/bin/phpunit --coverage-html coverage-report
在这个非 Laravel 示例中,代码覆盖率报告正确显示了测试覆盖的
app
和 modules
命名空间。
您可以在 https://github.com/iwasherefirst2/poc-coverage
查看我的示例的完整存储库Laravel 中的问题:
当我在具有相同结构和配置的新 Laravel 10.48.24 项目中复制此设置时,覆盖率报告无法包含模块文件夹,即使它的测试成功通过。
这是 Laravel 的特定信息:
两个项目都使用相同的 PHPUnit 版本,Laravel 中的测试是普通的单元测试 (
use PHPUnit\Framework\TestCase
)。然而,我的 Laravel 应用程序的覆盖率报告仅包含应用程序命名空间,完全省略了模块。
这也是完整的存储库,请查看https://github.com/iwasherefirst2/poc-laravel-coverage-modules
我尝试过的:
主要观察结果:
问题: 为什么 PHPUnit 代码覆盖率报告无法包含 Laravel 中的模块命名空间,即使测试正在运行并通过?这可能与 Laravel 的 PHPUnit 集成或自动加载配置有关吗?如何解决这个问题并确保 Laravel 中两个命名空间的完全覆盖?
经过彻底调查,我发现 Laravel 存储库和非 Laravel 存储库之间的区别在于 Laravel 设置中的代码覆盖期间使用了
PCOV
,而非 Laravel 存储库依赖于 Xdebug
。
PCOV
处理根级别多个目录的代码覆盖率似乎存在问题。这导致 modules
目录被排除在 Laravel 存储库的覆盖率报告之外。
要解决此问题,您可以禁用
PCOV
并使用 Xdebug
。
修改您的 Dockerfile 以完全排除
PCOV
。只需从安装步骤中删除 php8.2-pcov
软件包即可:
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
如果无法删除
PCOV
,您可以在覆盖运行期间通过传递 pcov.enabled=0
指令手动禁用它:
sail php -d pcov.enabled=0 ./vendor/bin/phpunit --coverage-text
确保您的
phpunit.xml
文件包含适当的代码覆盖率配置,具体取决于您的 PHPUnit 版本。
使用带有
<filter>
部分的 <whitelist>
标签:
<filter>
<whitelist>
<directory suffix=".php">app</directory>
<directory suffix=".php">modules</directory>
</whitelist>
</filter>
使用
<source>
切换到 <include>
标签:
<source>
<include>
<directory suffix=".php">app</directory>
<directory suffix=".php">modules</directory>
</include>
</source>