Api Platform/Symfony+PHPUnit:多构造参数ApiTestCase服务注入方案
问题根因说明
所有依赖注入方案失效、容器取服务报错的核心原因有两点:
- PHPUnit测试类实例由PHPUnit框架独立实例化,不属于Symfony/API Platform的DI容器托管范围,因此构造函数自动装配、
@required注解注入、services.yaml中手动绑定参数/配置calls方法这类容器级别的注入逻辑,完全不会作用在测试类上,此类方案仅对容器托管的业务服务生效。 - setUp方法中直接通过
self::$kernel->getContainer()获取的是编译后的生产容器,该容器会在编译阶段内联、移除非公共服务,且kernel本身是synthetic服务,未完成测试环境初始化流程时直接访问会抛出异常,无法直接获取api_platform.iri_converter服务。
可行实现方案
直接在setUp方法中通过KernelTestCase提供的测试专用容器获取服务即可,完整基类示例代码如下:
<?php namespace App\Tests; use ApiPlatform\Api\IriConverterInterface; use ApiPlatform\Symfony\Bundle\Test\ApiTestCase; abstract class BaseApiTestCase extends ApiTestCase { protected IriConverterInterface $iriConverter; protected function setUp(): void { parent::setUp(); self::bootKernel(); // 通过测试专用容器获取IriConverter服务,不要直接访问kernel持有的生产容器 $this->iriConverter = static::getContainer()->get('api_platform.iri_converter'); // API Platform 3.x+ 版本推荐直接用接口类名获取,无需硬写服务ID: // $this->iriConverter = static::getContainer()->get(IriConverterInterface::class); } /** * 快捷获取实体IRI的封装方法,供子类测试用例直接调用 */ protected function generateEntityIri(object $entity): string { return $this->iriConverter->getIriFromResource($entity); } }
补充注意事项
- 如果测试用例中已经通过
static::createClient()创建了API测试客户端,不需要重复调用bootKernel(),可以直接通过$client->getContainer()获取同一个测试容器取服务,效果完全一致。 - 不要尝试修改测试类构造函数适配容器注入,PHPUnit实例化测试类时会自动传入测试名称、数据集等参数,自定义构造函数很容易和PHPUnit的原生实例化逻辑冲突,触发额外报错。
- 测试专用容器默认开启了服务访问权限,不会在编译阶段移除API Platform的内部服务,可直接获取所有标记为测试可访问的服务,不存在服务被内联移除的问题。
内容的提问来源于stack exchange,提问作者Bricklet
相关产品推荐
相关产品推荐

