php主流单元测试框架是phpunit,需用vendor/bin/phpunit运行;测试类名以test结尾、方法以test开头;依赖须构造注入并可mock;断言优先用assertequals而非assertthat或assertsame。

PHP单元测试该用哪个框架
PHP生态里真正主流、维护活跃、文档完整的单元测试框架只有 PHPUnit。别被“phpspec”“ParaTest”或某些博客提过的冷门工具带偏——它们要么定位不同(如 phpspec 是行为驱动,不替代单元测试),要么只是并行执行层(如 ParaTest 本质还是跑 PHPUnit)。你装了 phpunit/phpunit 就够了,其他都是锦上添花甚至画蛇添足。
常见错误现象:composer require phpunit/phpunit 装完直接运行 phpunit 报错“command not found”。这是因为新版 PHPUnit 默认不安装全局二进制,得用 vendor/bin/phpunit。
- 用 Composer 安装:运行
composer require --dev phpunit/phpunit - 运行测试:必须用
./vendor/bin/phpunit(Linux/macOS)或vendor\bin\phpunit(Windows) - 别手贱加
--global,全局安装容易和项目 PHP 版本/依赖冲突
写第一个测试类要注意什么
不是所有类都值得测,但只要你想测,就得让被测代码可被实例化、方法可被调用、依赖可被替换。这意味着:别在构造函数里干重活(比如连接数据库)、别用 new 硬编码依赖、别把逻辑塞进静态方法里——否则你写的不是单元测试,是集成测试的残废版。
典型错误场景:测试一个发邮件的服务,结果每次跑测试真发一封邮件出去;或者测试一个读配置的类,它直接 file_get_contents('/etc/app.conf'),根本没法 mock。
立即学习“PHP免费学习笔记(深入)”;
绿色大气办公家具类企业织梦模板是以织梦最新内核来进行开发的模板,该模板属于家具行业,装修企业,家装类,属于企业通用,装修设计、家具生产等企业均可以使用该模板,页面简洁简单,容易管理,DEDE5.5内核以上都可以使用;附带测试数据!模板特点:简洁美观大方小清新的设计风格,图片展示效果绝佳。页面结构简单,利于SEO的优化,模板后台易于管理。使用程序:织梦DEDECMS5.5以上版本都可以使用。温馨提示
- 测试类名必须以
Test结尾,比如UserRepositoryTest - 测试方法名必须以
test开头,比如testCanCreateUserFromValidData - 被测类尽量通过构造函数注入依赖,而不是在方法里
new出来 - 用
$this->createMock(ClassName::class)替代真实对象,尤其对 I/O、网络、时间等不稳定依赖
assertThat 和 assertEquals 到底用哪个
别用 assertThat。这是 JUnit 遗留风格,在 PHPUnit 里既冗长又无必要。现代写法全部用直白的断言函数,比如 assertEquals、assertTrue、assertNull。它们语义清晰、报错信息友好、IDE 支持好。
容易踩的坑是过度使用 assertSame(严格比较)代替 assertEquals(宽松比较)。比如比较两个数组,内容一样但键顺序不同,assertSame 就会失败,而你其实只关心值是否一致。
- 字符串、数字、布尔、简单数组:优先用
assertEquals - 要检查是否是同一对象引用(比如单例、装饰器链):才用
assertSame - 验证异常:用
$this->expectException(\Exception::class),别 try-catch + fail() - 验证输出(如 echo):用
$this->expectOutputString('hello'),别自己 ob_start()
测试数据库操作怎么避免污染和变慢
单元测试不该连真实数据库。哪怕你用 SQLite 内存库,只要走 PDO 连接,就不再是纯单元测试——它依赖外部状态、启动慢、容易因并发失败。真正靠谱的做法是:把数据库交互封装成接口,测试时 mock 接口行为。
比如你有个 UserRepository,它依赖 DatabaseConnection。不要在测试里 new 一个 SQLite 实例,而是让 UserRepository 构造函数接收 DatabaseConnectionInterface,然后在测试中传入 $mock = $this->createMock(DatabaseConnectionInterface::class),再指定 $mock->method('query')->willReturn($fakeResult)。
- 真实数据库操作属于集成测试范畴,应单独放在
tests/Integration目录,用phpunit --testsuite integration单独跑 - 如果非要用内存 SQLite,记得每个测试用全新 DB 文件或
:memory:,且不能跨测试复用连接 - 时间相关逻辑(如
date('Y-m-d'))同样要抽象,用接口注入当前时间,测试时固定返回某一天
最常被忽略的一点:测试命名里藏逻辑。比如写个 testUserIsCreated,但里面没 assert 任何东西,只调用了创建方法——这根本不算测试,只是在跑副作用。每个测试必须有至少一个 assert,且 assert 的目标要明确、可验证、与方法职责对齐。










