PHPUnit要求测试文件以Test.php结尾、类名以Test结尾、方法以test开头或用@test注解;需继承TestCase、配置phpunit.xml、正确设置autoload-dev,否则测试不被识别或跳过。

PHPUnit 不是“写个断言就完事”的工具,它要求测试用例与被测代码在结构、生命周期和依赖上严格对齐;没配好 phpunit.xml 或没声明 test 方法命名规范,测试根本不会被识别。
怎么让 PHPUnit 找到并运行你的测试文件
PHPUnit 默认只扫描以 Test.php 结尾的文件,且类名必须以 Test 结尾(如 CalculatorTest),方法名必须以 test 开头(如 testAddReturnsCorrectResult)或用 @test 注解标记。不满足任一条件,该方法就不会被当作测试执行。
- 文件路径建议放在
tests/目录下,与src/平级 - 类必须
extends \PHPUnit\Framework\TestCase,否则无法调用$this->assertEquals()等断言 - 若用
composer require --dev phpunit/phpunit安装,确保vendor/bin/phpunit可执行;直接运行phpunit命令失败,大概率是因为没加vendor/bin/到$PATH或用了全局安装的老版本
assert 用错类型会静默失败,不是报错而是跳过
比如你写了 $this->assertEquals(4, $result),但 $result 是字符串 "4",默认开启严格类型比较(PHP 8+ 默认行为),这个断言就会失败;而如果你本意是宽松比较,就得显式写成 $this->assertEquals(4, $result, '', 0.0, 10, true) —— 第六个参数 true 表示忽略类型。但更常见也更安全的做法是用专用断言:
- 判断是否为整数:用
$this->assertIsInt($result) - 判断值相等且类型一致:用
$this->assertSame(4, $result) - 判断数组结构一致:用
$this->assertEqualsCanonicalizing([1,2], $result)(忽略顺序) - 错误信息里出现
Failed asserting that '4' is equal to 4.,说明你正踩在这个坑上
测试私有方法?别试了,先重构
PHPUnit 无法直接调用 private 或 protected 方法,强行用反射不仅难维护,还意味着你在测试实现细节而非行为。真实场景中,95% 的所谓“必须测私有方法”都源于函数职责过重或状态耦合太紧。
立即学习“PHP免费学习笔记(深入)”;
- 把私有逻辑拆成独立的、
public的小工具类,再单独测试它 - 如果私有方法只是做数据预处理,那就通过公共方法的输入输出覆盖它(例如传入边界值,看最终返回是否符合预期)
- 真要用反射——仅限调试:用
$reflector = new \ReflectionClass(Calculator::class); $method = $reflector->getMethod('doInternalCalc'); $method->setAccessible(true); $method->invoke($instance, ...$args);,但上线前必须删掉
为什么 phpunit.xml 不生效?路径和命名大小写是关键
PHPUnit 从当前工作目录开始找 phpunit.xml 或 phpunit.xml.dist,找不到就用默认配置。很多人把文件放在 tests/ 里却在项目根目录外运行命令,或者写成 PhpUnit.xml(Windows 下可能侥幸成功,Linux/macOS 下完全不认)。
- 最小可用配置只需包含
<testsuites><testsuite name="unit"><directory>tests/</directory></testsuite></testsuites> - 若要排除某些测试,用
<exclude>tests/Integration/</exclude>,注意路径是相对于配置文件所在目录的 - 用
phpunit --configuration phpunit.xml --debug可看到它实际加载了哪些测试文件,比猜快得多
最常被忽略的是测试类的自动加载——composer.json 里没配好 "autoload-dev",导致 use App\Calculator; 在测试里报 Class not found;这问题不报错在测试启动阶段,而是直接跳过整个测试类,连 setUp() 都不会触发。



















