Symfony 6.2:通用可用性测试中查询数据库的内核启动问题
解决Symfony测试数据提供者中内核提前启动的异常问题
核心问题根源
数据提供者的执行时机早于测试方法,在数据提供者里调用static::getContainer()会直接启动内核,而后续测试方法中的createClient()会再次尝试启动内核,触发LogicException。
可行解决方案
方案1:在测试类初始化阶段提前启动内核并复用容器
在测试类的setUpBeforeClass()方法中提前创建客户端,将容器实例保存为静态类属性,数据提供者直接复用这个已启动的容器:
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; class BlogPostAvailabilityTest extends WebTestCase { private static $container; public static function setUpBeforeClass(): void { $client = static::createClient(); self::$container = $client->getContainer(); } /** * @dataProvider blogPostUrlsProvider */ public function testBlogPostAvailability(string $url): void { $client = static::createClient(); $client->request('GET', $url); $this->assertResponseIsSuccessful(); } public static function blogPostUrlsProvider(): iterable { /** @var \App\Repository\BlogPostRepository $repo */ $repo = self::$container->get(\App\Repository\BlogPostRepository::class); $posts = $repo->findAll(); foreach ($posts as $post) { yield [$post->getUrl()]; } } }
说明:setUpBeforeClass()在所有测试方法执行前仅运行一次,提前完成内核启动和容器保存,数据提供者直接复用实例,避免重复启动内核。
方案2:将仓库调用逻辑移至测试方法内
如果不需要为每篇文章生成独立测试用例,可把仓库查询和URL校验逻辑合并到单个测试方法中:
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; class BlogPostAvailabilityTest extends WebTestCase { public function testAllBlogPostsAreAvailable(): void { $client = static::createClient(); $repo = $client->getContainer()->get(\App\Repository\BlogPostRepository::class); $posts = $repo->findAll(); foreach ($posts as $post) { $client->request('GET', $post->getUrl()); $this->assertResponseIsSuccessful(sprintf('校验失败:文章 "%s"', $post->getTitle())); } } }
说明:该方式避免了数据提供者中启动内核的冲突,适合不需要单独统计单篇文章测试结果的场景。
方案3:通过测试依赖提前初始化内核
创建前置测试方法完成内核启动和仓库实例化,数据提供者依赖该方法的执行结果:
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; class BlogPostAvailabilityTest extends WebTestCase { private static $repo; public function testKernelBoot(): void { $client = static::createClient(); self::$repo = $client->getContainer()->get(\App\Repository\BlogPostRepository::class); $this->assertNotNull(self::$repo); } /** * @dataProvider blogPostUrlsProvider * @depends testKernelBoot */ public function testBlogPostAvailability(string $url): void { $client = static::createClient(); $client->request('GET', $url); $this->assertResponseIsSuccessful(); } public static function blogPostUrlsProvider(): iterable { $posts = self::$repo->findAll(); foreach ($posts as $post) { yield [$post->getUrl()]; } } }
说明:@depends注解确保testKernelBoot()优先执行,提前完成仓库初始化,数据提供者可直接使用实例,不会触发内核重复启动。
关键注意事项
- 数据提供者为静态方法,需用静态属性保存容器或仓库实例
- 禁止在数据提供者中直接调用
static::getContainer(),必须通过提前启动的客户端获取容器 - Symfony的
WebTestCase内核默认是单例,但数据提供者执行时内核未完成正确初始化,会导致后续createClient()报错
内容的提问来源于stack exchange,提问作者Olray
相关产品推荐
相关产品推荐

