本文目录导读:

PHPUnit 的版本迭代较快,不同大版本(如 8.x → 9.x → 10.x → 11.x)之间的升级通常包含重大变更、新特性和弃用功能。
由于你未指定具体从哪个版本升级到哪个版本,我将以最受关注的两个升级节点(8.x → 9.x 和 9.x/10.x → 11.x)作为核心,并简要说明 10.x 和 11.x 的新特性。
如果你需要更具体的版本比较(7.x → 9.x),请补充说明。
PHPUnit 8.x → 9.x (重大架构升级)
这是 PHPUnit 历史上一次“清理门户”的重大升级,引入了类型化和注解革命。
核心变化:基于注解的配置
- 弃用:
@expectedException、@expectedExceptionMessage、@expectedExceptionCode。 - 替代:强制使用
$this->expectException()、$this->expectExceptionMessage()等方法。 - 影响:所有基于注解的异常断言都失效了,必须改为方法调用。
类型系统彻底变革
- 强制类型:测试类必须实现
TestCase,且所有测试方法必须返回void(即public function testSomething(): void)。 - 严格类型声明:
PHPUnit\Framework\TestCase构造函数签名变为( ?string $name = null, array $data = [], $dataName = '' )并强制类型。 - Mock 对象:对 Mock 对象的类型感知更强,减少了运行时错误。
新特性
@covers注解改进:支持更细粒度的覆盖范围(如@covers \MyClass::method)。setUpBeforeClass()和tearDownAfterClass()支持返回值:可以返回void或null。- 更好的 PHP 8.0 支持:完全兼容 union types、named arguments(但有限制)。
移除项
- 移除:对
@runInSeparateProcess的某些旧行为支持。 - 移除:
assertPreConditions()、assertPostConditions()的默认行为(需显式返回void)。
PHPUnit 9.x/10.x → 11.x (最新架构,2024-2025版本)
PHPUnit 11 是一个更现代、更严格的版本,彻底告别了旧 PHPDoc 注解,并向静态分析友好迈进。
终结“纯 PHPDoc 注解”时代 (Attribute 时代)
- 强制使用 PHP 8 Attributes:
@test、@dataProvider、@depends、@group等老注解完全移除。 - 新写法:
#[Test]/#[DataProvider(‘method’)]/#[Depends(‘testA’)]/#[Group(‘fast’)]
- 影响:不升级 Attributes,测试将直接报错中断。
更严格的类型系统
- 禁止非 void 返回值:测试方法必须返回
void(之前版本警告,现在报错)。 setUp()和tearDown():签名必须为protected function setUp(): void,不能传入参数,且必须调用parent::setUp()(否则报错)。- 数据提供器 (Data Provider):必须返回
iterable类型,不能返回array(未指明索引的数组会警告)。
Mock 系统的突破
createMock()默认行为改变:不再自动调用__construct()(除非显式调用willReturn()或with()),这更容易创建隔离测试。- 禁用
returnValueMap():多数场景下被willReturnCallback()替代。 expects()方法的once():现在严格区分->once()->method(…)和->method(…)->once()的书写顺序。
测试执行引擎优化
- 并行测试 (Parallel Testing) 正式稳定:无需
--processes扩展,内置--parallel参数(需安装phpunit/phpunit≥ 11.0)。 - 覆盖率报告改进:支持 HTML + 行覆盖率 + 分支覆盖率混合显示。
- 精确的错误显示:断言失败时,直接显示变量类型和值,不再截断长字符串。
弃用项 (将在 12.x 移除)
assertInternalType()系列(已弃用多年,现在完全移除)。@requires注解(需改为#[RequiresPhp(‘8.1’)])。expectExceptionCode()和expectExceptionMessageRegExp()的某些旧行为。
升级注意事项(通用清单)
无论你从哪个版本升级,以下都是需要检查的关键点:
| 检查项目 | 旧写法 (需修改) | 新写法 (推荐/必须) |
|---|---|---|
| 测试方法 | public function testSomething() |
public function testSomething(): void |
| 异常断言 | @expectedException \InvalidArgumentException |
$this->expectException(\InvalidArgumentException::class); |
| 数据提供器 | @dataProvider dataForTest |
#[DataProvider(‘dataForTest’)] (或 #[DataProvider(DataProvider::class, ‘method’)]) |
| 依赖测试 | @depends testA |
#[Depends(‘testA’)] |
| 分组(groups) | @group slow |
#[Group(‘slow’)] |
| setUp/tearDown | protected function setUp() |
protected function setUp(): void + 必须调用 parent::setUp() |
| Mock创建 | $this->getMockBuilder(...)->getMock() |
多用 $this->createMock(),减少 getMockBuilder |
| 返回值 | 不返回 (void) | 必须显式 void |
| PHP版本要求 | PHP 7.4 / 8.0 | PHP 11.x 要求 PHP 8.1+ (推荐 PHP 8.2+) |
升级工具推荐
- Rector:自动扫描并修复注解 -> Attributes 的转换(
rector.php配置中开启SetList::PHPUNIT_90、SetList::PHPUNIT_100等)。 - PHP-CS-Fixer:配合
@PHPUnit100Migration:risky规则集。 - 手动检查清单:运行
phpunit --migrate-configuration(生成新版phpunit.xml.dist)和phpunit --list-suites。
- 从 8.x 到 9.x:必须将注解异常改为方法调用,并统一返回
void,这是最痛苦的迁移点。 - 从 9.x/10.x 到 11.x:必须将
@test/@dataProvider等所有注解改为 PHP 8 Attributes,并适配更严格的类型签名。 - 最推荐路径:如果项目刚启动,直接使用 PHPUnit 11.x;如果老旧项目,建议先升到 9.6(稳定版),再用 Rector 一步到位升到 11.x。
如果你有具体的 phpunit.xml 配置或测试代码片段,可以提供给我,我可以帮你分析具体的冲突点。