必须用 composer require --dev phpunit/phpunit:^9.6(PHP 7.4)、^10.5(PHP 8.0–8.1)或 ^11.0(PHP 8.2+),配对 phpunit.xml(根目录)、autoload-dev 映射及 bootstrap="vendor/autoload.php",缺一不可。

直接用 composer require --dev phpunit/phpunit 装上,但测试跑不起来,90% 是因为 autoload-dev 没生效、phpunit.xml 没被读到、或测试类根本没被自动加载——三者缺一不可。
怎么装 PHPUnit 才不会版本爆炸
PHPUnit 和 PHP 版本强绑定,装错连 TestCase 都找不到:
- PHP 7.4 项目 → 必须用
composer require --dev phpunit/phpunit:^9.6 - PHP 8.0–8.1(如 Laravel 10)→ 推荐
^10.5 - PHP 8.2+ → 可试
^11.0,但确认项目没用已移除的phpunit-skeleton-generator - 绝对别用
--latest:它可能拉到 v11,而你本地是 PHP 8.1,直接报Declaration of PHPUnitFrameworkTestCase::setUp(): void must be compatible
phpunit.xml 为什么总不生效
它不报错,只静默退回到默认行为(比如只扫当前目录下 *Test.php),常见失效点:
- 文件名必须是
phpunit.xml或phpunit.xml.dist,且放在和composer.json同级的根目录;phpunit.xml.php、tests/phpunit.xml全无效 -
bootstrap="vendor/autoload.php"必须写在<phpunit></phpunit>标签里,漏掉这句,use TestsUnitExampleTest就会报Class not found -
<directory>tests</directory>是相对路径,以配置文件所在目录(即项目根目录)为基准;写成./tests或../tests多数情况失败 - PHP 9.3+ 已废弃
<whitelist></whitelist>,改用<coverage><include><directory>src</directory></include></coverage>,否则覆盖率报告为空
测试类找不到?先查 autoload-dev 和命名空间对齐
即使 phpunit.xml 写对了,只要路径、命名空间、类名三者不一致,就会报 Class 'TestsUnitExampleTest' not found:
立即学习“PHP免费学习笔记(深入)”;
- 文件路径必须是
tests/Unit/ExampleTest.php - 文件内必须声明
namespace TestsUnit;(注意结尾分号,且不能多空格) - 类名必须是
ExampleTest,且必须继承PHPUnitFrameworkTestCase(旧写法PHPUnit_Framework_TestCase在 PHP 7.4+ 已彻底废弃) -
composer.json中autoload-dev必须包含该映射:"autoload-dev": { "psr-4": { "Tests\": "tests/" } } - 改完后必须运行
composer dump-autoload,否则新增的映射不生效
CI 里 test 报 Class not found,但本地能过
根本原因不是测试代码问题,而是 CI 默认执行 composer install --no-dev,导致两件事同时失效:
-
autoload-dev不加载 → 测试基类(如tests/Support/TestCase.php)找不到 - 主命名空间
autoload配错 → 比如类在src/Calculator.php、命名空间是MyPackage,但composer.json里写的是"App\": "src/",CI 就永远加载不到MyPackageCalculator - 验证方法:CI 脚本里加一行
composer dump-autoload --no-dev && php -r "echo class_exists('MyPackage\Calculator') ? 'ok' : 'fail';" - 别把测试辅助类放进
autoload-dev后又在src/里use它——生产环境 autoload 不含autoload-dev,CI 必炸
最常被忽略的其实是 bootstrap="vendor/autoload.php" 这一句:删掉它,整个自动加载链就断了,但 PHPUnit 不报错,只默默跳过所有测试文件。不是“没写对”,是“根本没触发”。



















