Symfony如何在PHPUnit测试中注入AuthorizationChecker?
问题背景
同事修改了服务代码,新增了基于AuthorizationCheckerInterface的权限校验:
$this->authorizationChecker->isGranted(Roles::ROLE_PERSON_VIEW);
但测试代码未适配,当前测试通过以下方式创建待测试服务:
protected function getService(string $id): ?object { $kernel = static::createKernel(); $kernel->boot(); return $kernel ->getContainer() ->get($id); } /** @var AuthorizationCheckerInterface $authorizationChecker */ $authorizationChecker = $this->getService('AuthorizationChecker'); $this->manager = new Manager( $entityManager, $fooService, $baaService, $authorizationChecker );
执行测试时抛出错误:
ServiceNotFoundException: You have requested a non-existent service "AuthorizationChecker"
尝试两种方案均存在问题:
- 模拟
AuthorizationCheckerInterface:未定义返回值时返回null,定义返回值则无法验证权限逻辑与业务代码的协同性(已模拟用户权限,需要真实校验逻辑) - 手动创建
AuthorizationChecker:遇到TokenStorageInterface和AccessDecisionManagerInterface的依赖问题
最佳测试方案
方案1:使用正确的官方服务ID直接获取
Symfony中AuthorizationCheckerInterface对应的标准服务ID是security.authorization_checker,替换测试中的服务ID即可:
$authorizationChecker = $this->getService('security.authorization_checker');
配合测试中已模拟的用户Token(比如通过$this->loginUser($user)方法设置登录用户),就能完整验证权限逻辑与业务代码的协同性,无需额外配置依赖。
方案2:手动构建带真实逻辑的AuthorizationChecker
如果需要更灵活的控制,可手动构建依赖链,保留真实权限校验逻辑的同时使用自定义Token:
- 模拟TokenStorage并注入已准备好的用户Token:
$tokenStorage = $this->createMock(TokenStorageInterface::class); $tokenStorage->method('getToken')->willReturn($yourMockedToken); // $yourMockedToken为你已模拟的用户Token
- 从容器获取真实的权限决策管理器:
$accessDecisionManager = $this->getService('security.access.decision_manager');
- 实例化真实的AuthorizationChecker:
use Symfony\Component\Security\Core\Authorization\AuthorizationChecker; $authorizationChecker = new AuthorizationChecker( $tokenStorage, $accessDecisionManager, $this->getService('security.authentication.trust_resolver') );
此方案既保留了Symfony原生的权限校验逻辑,又能完全控制测试用的用户权限。
方案3:基于WebTestCase的功能测试适配
如果是功能测试场景,直接使用WebTestCase的内置方法简化流程:
$client = static::createClient(); $client->loginUser($yourTestUser); // 设置测试登录用户 $authorizationChecker = $client->getContainer()->get('security.authorization_checker'); $this->manager = new Manager( $entityManager, $fooService, $baaService, $authorizationChecker );
loginUser方法会自动将用户Token注入容器的授权服务,无需手动处理依赖。
内容的提问来源于stack exchange,提问作者Calamity Jane
相关产品推荐
相关产品推荐

