PHPUnit 必须本地安装并立即集成到项目中,通过 Composer 安装、配置 composer.json 脚本、严格遵循 TestCase 继承与 test 方法命名规则、按返回类型选择 assertEquals 或 assertSame、前置调用 expectException 才能确保测试真实有效。

phpunit 不是“学完再用”的工具,而是你写完第一行业务代码就得立刻配上的基础设施。没它,你改个 add() 都不敢确定没把 subtract() 带崩。
怎么让 phpunit 命令在项目里直接跑起来
别碰全局安装,也别手动改 PATH。Composer 本地装是唯一靠谱路径:composer require --dev phpunit/phpunit ^10.5(PHP 8.2+ 推荐)
装完立刻验证:./vendor/bin/phpunit --version,有输出就说明依赖和自动加载都通了。
顺手加一行脚本到 composer.json 的 scripts 区块:"test": "phpunit"
之后只要 composer test 就能跑,不用记路径、不依赖 shell 环境变量。
TestCase 继承和 test 方法命名为什么不能错
PHPUnit 不靠文件名或注释识别测试,只认两个硬规则:
- 测试类必须 extends PHPUnit\Framework\TestCase
- 测试方法必须是 public、无参数、名字以 test 开头(比如 testAdd),或带 @test 注解
- 忘写 use PHPUnit\Framework\TestCase 或漏掉 extends,报错是 Class 'PHPUnit\Framework\TestCase' not found,但真正原因常被误判为“没装好”
- 写成 addTest() 或 private function testAdd()?PHPUnit 直接跳过,不报错、不提醒、不运行——静默失效比报错更危险
assertEquals 和 assertSame 到底该选哪个
这不是风格问题,是类型契约问题:
- assertEquals(5, $result):松散比较(==),"5"、5.0、5 全部通过
- assertSame(5, $result):严格比较(===),值和类型都得对,"5" 直接失败
- 如果你的方法声明返回 int(如 public function add(int $a, int $b): int),测试就必须用 assertSame;否则你可能把一个悄悄转成字符串的 bug 当成正常行为放过去了
- 同理,返回 string 或 array 时,也要按实际类型选断言,别图省事全用 assertEquals
测试抛异常时,expectException 为什么必须写在调用前
它不是 try-catch,而是“前置声明”:
- $this->expectException(\InvalidArgumentException::class); 这行的意思是:“接下来这一句代码,我预期它会抛这个异常”
- 如果异常没抛、抛错类、或者执行流根本没走到那行(比如提前 return 了),测试就失败
- 把它写在 $this->calculator->divide(10, 0); 后面?没用,PHPUnit 已经错过捕获窗口,会报 “Expected exception InvalidArgumentException not thrown”
- 多个异常场景要拆成独立测试方法,别试图在一个方法里混着测正常路径和异常路径
真实项目里最容易被忽略的点:测试文件没加 use、bootstrap 路径配错、断言类型和函数返回类型不一致——这些问题不会让你的代码跑不起来,但会让你的测试“看起来通过”,实则完全失去防护价值。



















