phpunit版本需严格匹配php版本:php 7.4用9.6.x,8.0–8.2用10.x,8.3+用11;setup/teardown慎用以防状态污染;断言选assertsame()保类型安全;私有方法应通过公共接口测试;测试文件必须以test.php结尾。

PHPUnit 10+ 默认不支持 PHP 7.4 及更早版本,如果你用的是 PHP 8.1+,直接装最新版即可;但若项目卡在 PHP 7.4,必须锁定 phpunit/phpunit 到 9.6.x 版本,否则 composer install 会失败或测试根本跑不起来。
安装 PHPUnit 要匹配 PHP 版本
Composer 安装不是“最新就好”。PHP 7.4 只能用 PHPUnit 9.6(LTS),PHP 8.0–8.2 推荐 PHPUnit 10.x,PHP 8.3+ 才能用 PHPUnit 11。装错版本会导致 Class 'PHPUnit\Framework\TestCase' not found 或 Declaration of ... must be compatible with ... 这类致命错误。
实操建议:
- 查当前 PHP 版本:
php -v - PHP 7.4 → 运行:
composer require --dev phpunit/phpunit:^9.6 - PHP 8.1+ → 运行:
composer require --dev phpunit/phpunit:^10.5 - 别加
-g全局安装——不同项目可能依赖不同 PHPUnit 大版本,全局装反而容易冲突
setUp() 和 tearDown() 不是必须写,但状态污染常从这里开始
很多初学者以为每个测试方法都“天然隔离”,其实 $this 是同一个 TestCase 实例(除非显式配置 backupGlobals="true")。如果在某个测试里改了静态属性、全局数组或单例状态,下一个测试可能读到脏数据。
常见错误现象:
- 测试 A 写了
SomeService::$cache = [],测试 B 突然报Undefined index - 数据库测试中没清空临时表,第二次运行时主键冲突
实操建议:
- 只在真正需要初始化/清理时才重写
setUp()/tearDown(),避免无谓开销 - 优先用局部变量和新构造对象,而不是复用
$this->foo—— 减少隐式依赖 - 如需隔离全局状态,可在
phpunit.xml中启用:backupGlobals="true",但会明显拖慢执行速度
断言选 assertEquals() 还是 assertSame()?类型敏感场景必须分清
assertEquals() 做松散比较(类似 ==),assertSame() 做严格比较(类似 ===)。对返回值类型敏感的逻辑(比如 API 响应要求整数不能是字符串 "1"),用错断言会掩盖 bug。
示例:
// 假设 $response->getStatusCode() 返回 int 200 $this->assertEquals(200, $response->getStatusCode()); // ✅ 通过,但掩盖了返回 string 的风险 $this->assertSame(200, $response->getStatusCode()); // ❌ 若实际返回 "200",立刻失败
使用场景建议:
- 验证 DTO 属性、JSON 解码后字段、数据库读取的原始值 → 优先
assertSame() - 验证计算结果、拼接字符串、经过
(int)强转后的值 → 可用assertEquals() - 数组内容比对一律用
assertEquals()(assertSame()对数组键顺序敏感,易误报)
测试私有方法?别费劲,重构接口或测行为
PHPUnit 无法直接调用 private 方法,强行用反射(ReflectionMethod + setAccessible(true))不仅难维护,还让测试过度绑定实现细节。一旦你把私有方法改成 protected 或抽成独立类,所有反射调用全挂。
更务实的做法:
- 检查该私有方法是否真有必要存在——它是不是承担了可独立验证的职责?如果是,把它提取成 public 方法(放在工具类或 service 中)
- 如果只是内部逻辑分支,那就通过 public 方法的输入/输出覆盖它。例如:私有方法负责格式化手机号,就给 public 方法传不同格式的号码,断言最终响应是否符合预期
- 真要调试私有逻辑?加日志或 xdebug 断点,别靠测试“撬锁”
最常被忽略的一点:测试文件命名必须以 Test.php 结尾,且类名必须和文件名一致(如 UserTest.php 里是 class UserTest),否则 phpunit 默认扫描器直接跳过——连报错都不会有,安静地告诉你“0 tests executed”。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











