
本文详解在重构为命名空间模块后,phpunit 代码覆盖率无法覆盖 `./module/*/src` 目录的常见原因及解决方案,重点强调自动加载配置与 pcov 扩展冲突的排查方法。
当项目从扁平结构升级为模块化架构(如 ./module/module-one/src)后,即使已在 phpunit.xml 的 <coverage><include> 中显式添加对应目录,PHPUnit 生成的覆盖率报告仍仅显示 ./app 下的文件——这通常并非配置语法错误,而是底层执行环境与自动加载机制未同步导致的典型问题。以下是系统性排查与修复步骤:
✅ 1. 确保模块目录已正确注册到 Composer 自动加载
PHPUnit 的代码覆盖率分析依赖于 实际被加载并执行的 PHP 类文件。若 ./module/module-one/src 中的类未被 Composer 自动加载(例如未声明 psr-4 映射),即使路径写入 <include>,Xdebug 也无法为其生成行覆盖率数据。
请检查 composer.json,为每个模块添加对应的 PSR-4 自动加载规则:
{
"autoload": {
"psr-4": {
"ModuleOne\": "module/module-one/src/",
"ModuleTwo\": "module/module-two/src/",
"ModuleThree\": "module/module-three/src/",
"App\": "app/"
}
}
}✅ 修改后务必运行:
立即学习“PHP免费学习笔记(深入)”;
composer dump-autoload
以刷新自动加载映射。这是覆盖率覆盖新模块的前提条件。
✅ 2. 禁用 PCOV 扩展(关键!)
您使用的环境包含 pcov(v1.0.8),而 PCOV 与 Xdebug 3.x 不兼容,且会主动接管代码覆盖率逻辑,导致 PHPUnit 忽略 <include> 配置、仅分析默认入口(如 ./app)或完全失效。
请确认 php.ini 或 xdebug.ini 中已禁用 PCOV:
; 确保以下配置存在且生效 pcov.enabled=0 ; 同时确保 Xdebug 已启用并支持覆盖率 xdebug.mode=coverage
验证方式:运行以下命令,确认输出中 无 pcov 相关扩展,且 xdebug.mode 包含 coverage:
php -v php --ini php -m | grep -i -E "(xdebug|pcov)" php -i | grep "xdebug.mode"
⚠️ 注意:若使用 Docker、PHP-FPM 或 CLI 多配置环境,请分别检查对应 SAPI 的 INI 文件(如 php -i | grep "Loaded Configuration File")。
✅ 3. 补充建议:优化 phpunit.xml 配置
虽然多 <directory> 写法本身合法,但为提升可维护性与明确性,推荐改用 <files> 块,并启用 processUncoveredFiles="true"(您已启用,很好):
<coverage processUncoveredFiles="true">
<include>
<directory suffix=".php">./app</directory>
<directory suffix=".php">./module/module-one/src</directory>
<directory suffix=".php">./module/module-two/src</directory>
<directory suffix=".php">./module/module-three/src</directory>
</include>
<!-- 可选:排除测试文件 -->
<exclude>
<directory suffix="Test.php">./tests</directory>
</exclude>
</coverage>最后,清理缓存并重新运行:
phpunit --coverage-html coverage/
✅ 总结
| 问题根源 | 解决动作 |
|---|---|
| 模块类未被加载 | 更新 composer.json + composer dump-autoload |
| PCOV 与 Xdebug 冲突 | 设置 pcov.enabled=0,启用 xdebug.mode=coverage |
| 配置未生效 | 验证 PHP CLI 使用的 INI 文件,重启相关服务(如必要) |
完成上述两步(自动加载 + PCOV 禁用),PHPUnit 将如实扫描并统计所有 <include> 目录下的已执行 PHP 文件,模块代码将完整出现在 HTML 覆盖率报告中。



















