PHPUnit测试真正写对需满足三条件:命令可执行、测试类能加载、断言不误报;须本地安装、手动引入autoload.php、正确设置setUp/tearDown以确保隔离性。

phpunit 命令能跑起来、测试类能加载、断言不误报——这三件事齐了,才算真正写对了 PHPUnit 测试。其余都是锦上添花。
phpunit 命令找不到?先确认是不是本地安装没走对路
全局安装 phpunit 在现代 PHP 项目里基本是陷阱:Composer 新版已弃用 composer global require,且 bin-dir 路径常被 shell 忽略(尤其 macOS/Linux 用了 Homebrew 或自定义 COMPOSER_HOME)。
- 统一用项目本地安装:
composer require --dev phpunit/phpunit - 运行必须走:
vendor/bin/phpunit(Linux/macOS)或vendor\bin\phpunit.bat(Windows) - 执行
which phpunit(macOS/Linux)或where phpunit(Windows),返回空就说明命令根本没注册进 shell 环境 - 别信“装完就能直接敲
phpunit”——除非你明确配过$PATH并验证过
Class 'PHPUnit\Framework\TestCase' not found?autoload-dev 没生效
这不是你少写了 use,而是 Composer 的自动加载机制压根没把 PHPUnit 的命名空间拉进来。
- 检查
composer.json是否有"autoload-dev"字段(哪怕只是空对象{}),没有就加一行 - 测试文件顶部必须显式包含:
require_once 'vendor/autoload.php';—— 即使你用了 PSR-4 映射,也得手动引一次启动入口 - 类名和路径要严格匹配:类
CalculatorTest必须放在tests/CalculatorTest.php,否则vendor/autoload.php找不到它 - 别用
phpunit tests/CalculatorTest.php直接跑单个文件,先确保phpunit --version成功,再让框架自己发现测试
assertEquals() 总失败?别怪 PHPUnit,先看值到底是不是“一样”
PHP 的比较逻辑比肉眼看到的复杂得多:浮点精度、数组键序、对象引用、不可见字符、null vs ''……这些都会让断言静默失败。
- 浮点数比较必须加容差:
$this->assertEquals(0.3, 0.1 + 0.2, '', 0.0001) - 数组内容一致但键顺序不同?用
assertEqualsCanonicalizing()(PHPUnit 9.3+),或手动ksort()后再比 - 字符串疑似相同却失败?用
bin2hex($str)查真实字节,揪出 BOM、\r\n、零宽空格 - 对象别直接
assertEquals($expected, $actual)—— 这是在比内存地址;改用assertInstanceOf()+assertNotNull()+ 关键属性断言
测试之间互相污染?setup/teardown 不是可选项
PHPUnit 默认每个 test* 方法单独执行,但它不会帮你重置 $_SERVER、静态属性、全局变量或单例状态。
立即学习“PHP免费学习笔记(深入)”;
- 所有共享初始化逻辑必须放
protected function setUp(): void里(注意返回类型声明) - 清理工作必须放
protected function tearDown(): void,比如关闭 mock、清空静态缓存、还原超全局变量 - 别在测试方法里用
echo、var_dump或修改$_ENV—— 它们会泄漏到下一个测试,导致行为不一致 - 依赖外部服务(数据库、HTTP)的测试,优先用
$this->createMock()替代真实调用,避免状态残留



















