symfony 7 默认兼容 phpunit 10.5+,要求 php 8.1+,废弃 phpunit 9 兼容层及 @dataprovider 数组语法,强制使用 expectexception() 与 expectexceptionmessage() 组合,并需通过 webtestcase 获取容器、显式启用 profiler、避免在 dataprovider 中传递不可序列化对象。

PHPUnit 10 是 Symfony 7 的默认兼容版本
Symfony 7 默认要求 phpunit/phpunit ^10.5,装低版本(比如 9.x)会直接报错:Class PHPUnit\Framework\TestCase not found。这是因为 Symfony 7 移除了对 PHPUnit 9 的兼容层,且 PHPUnit 10 强制使用 PHP 8.1+、废弃了 @dataProvider 中的数组语法(必须用 array() 或短数组 []),还把 expectException() 改为更严格的 expectException() + expectExceptionMessage() 组合。
- 初始化项目时运行
composer require --dev phpunit/phpunit:^10.5,别加^9.6 -
phpunit.xml.dist中确保bootstrap指向vendor/autoload.php,Symfony 7 不再自动生成tests/bootstrap.php - 测试类命名仍需以
Test结尾,但命名空间必须匹配实际路径(如App\Tests\Controller\DefaultControllerTest对应tests/Controller/DefaultControllerTest.php)
测试 Symfony 服务时别直接 new 实例
手动 new 服务会绕过容器,导致依赖注入失效、配置未加载、事件监听器不触发——尤其在测试带 @Route、@Security 或 Doctrine ORM 交互的服务时,结果和真实行为严重不符。
- 用
static::getContainer()获取完整容器(需继承Symfony\Bundle\FrameworkBundle\Test\WebTestCase) - 若只测纯逻辑类(无容器依赖),继承
PHPUnit\Framework\TestCase更轻量,但不能调用getContainer() - 需要模拟服务行为时,用
$this->createMock(ServiceInterface::class),而非Mockery或手写 stub——后者容易漏掉方法签名或返回类型 - 数据库测试务必用
Symfony\Bundle\FrameworkBundle\Test\KernelTestCase+self::bootKernel(),并显式调用$this->ensureKernelShutdown()防止连接泄漏
WebTestCase::createClient() 默认不启用 profiler
想查 SQL 查询次数、内存占用或事件调度链路?createClient() 默认关闭 profiler,$client->enableProfiler() 必须在发送请求前调用,否则 $client->getProfile() 返回 null。
- 正确写法:
$client = static::createClient(); $client->enableProfiler(); $client->request('GET', '/api/users'); $profile = $client->getProfile(); - 检查查询数:
$profile->getCollector('db')->getQueryCount() - 验证是否走了缓存:
$profile->getCollector('debug')->getSearchedPaths() - 注意:profiler 在 test 环境默认启用,但 client 需显式开启——这是 Symfony 测试层的隐式开关,不是配置问题
数据提供者(@dataProvider)里别传对象实例
PHPUnit 10 序列化 @dataProvider 返回值时,只支持标量、数组、null 和可序列化的简单对象。传 Doctrine 实体、Request 或 Container 就会报 Serialization of 'Closure' is not allowed。
- 数据提供者函数只能返回数组、字符串、整数、布尔值,或
new \stdClass()这类无闭包/资源属性的对象 - 需要复杂输入时,改用
setUp()中构造,或拆成多个测试方法 - 若坚持用 provider,把实体字段抽成数组:
return [['id' => 1, 'name' => 'foo']],然后在测试里重建对象 - 常见坑:provider 里调用
static::getContainer()会失败——此时 kernel 还没启动,provider 执行早于setUpBeforeClass()
WebTestCase 和 KernelTestCase 的生命周期差异:前者自动启动 kernel 并复用,后者每次测试都重 boot,但需要手动清理。跑得慢或报 “Too many connections” 时,先看是不是混用了两者又忘了 ensureKernelShutdown()。php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











