Symfony 7.2 Notifier组件异步消息测试失败排查求助
问题:NotifierInterface异步消息测试无法检测,ChatterInterface正常
生产环境中使用NotifierInterface发送异步消息功能正常,但测试环节无法检测到该服务发送的异步消息;而使用ChatterInterface发送消息的测试可正常通过。
测试不通过的场景(使用NotifierInterface)
<?php namespace App\Controller; // 省略必要命名空间 class HomeController extends AbstractController { #[Route(path: '/')] public function home( NotifierInterface $notifier, ) { $subject = 'Symfony Notifier'; $content = 'Message!'; $notification = new Notification( subject: $subject, channels: [ 'chat/telegram', ], ); $notification ->content($content) ->emoji('💕') ; $recipient = new Recipient( email: $adminEmail, phone: $adminPhone, ); $notifier->send( $notification, $recipient, ); return $this->render('home/index.html.twig'); } }
测试通过的场景(使用ChatterInterface)
<?php namespace App\Controller; // 省略必要命名空间 class HomeController extends AbstractController { #[Route(path: '/')] public function home( ?ChatterInterface $chatter, ) { $telegramOptions = new TelegramOptions(); $telegramMessage = (new ChatMessage('Hello, it is a new message')) ->transport('telegram') ->options($telegramOptions) ; if (null !== $chatter) { $chatter->send($telegramMessage); } return $this->render('home/index.html.twig'); } }
测试代码
<?php namespace App\Tests\Application\Controller; // 省略必要命名空间 class HomeControllerTest extends AbstractApplicationCase { public function testNotifierOneAsyncMessengeWasSent() { $client = static::createClient(); $client->followRedirects(true); // 请求发送异步通知的控制器方法 $crawler = $client->request('GET', '/'); $event = $this->getNotifierEvent(); // 第一个场景返回null $notification = $this->getNotifierMessage(); // 第一个场景返回null //###> 断言 ### // $this->assertQueuedNotificationCount(1); // 和下方效果一致 $this->assertQueuedNotificationCount(1, 'telegram'); /** 第一个场景报错: * Failed asserting that the Transport telegram has queued "1" emails (0 queued). │ │ C:\Workspace\SYMFONY\__SANDBOX__\drafts\vendor\symfony\framework- | bundle\Test\NotificationAssertionsTrait.php:32 │ C:\Workspace\SYMFONY\__SANDBOX__\drafts\tests\Application\Controller\HomeControllerTest.php:29 │ C:\Workspace\SYMFONY\__SANDBOX__\drafts\vendor\phpunit\phpunit\phpunit:104 */ if ($event instanceof MessageEvent) { $this->assertNotificationIsQueued($event); } if ($notification instanceof MessageInterface) { $this->assertNotificationSubjectContains($notification, 'Hello'); $this->assertNotificationTransportIsEqual($notification, 'telegram'); } //###< 断言 ### } }
配置文件
config/notifier.yaml
when@test: &test framework: notifier: chatter_transports: telegram: 'null://null' framework: notifier: message_bus: messenger.default_bus chatter_transports: telegram: '%env(TELEGRAM_DSN)%' channel_policy: urgent: - 'browser' high: - 'browser' medium: - 'browser' low: - 'browser' admin_recipients: - email: '%env(APP_ADMIN_EMAIL)%' phone: '%env(APP_ADMIN_PHONE)%'
config/messenger.yaml
framework: messenger: transports: sync: 'sync://' async: dsn: '%env(MESSENGER_TRANSPORT_DSN)%' options: queue_name: async retry_strategy: max_retries: 3 delay: 3000 multiplier: 2 max_delay: 10000 routing: # NOTIFIER 'Symfony\Component\Notifier\*': async
解决方案
1. 补全测试环境的Notifier配置
测试环境下的notifier.yaml仅配置了chatter_transports,缺少message_bus和与业务匹配的channel_policy,导致Notifier无法正确绑定消息总线、匹配传输通道。修改when@test块:
when@test: &test framework: notifier: message_bus: messenger.default_bus # 和生产环境一致绑定消息总线 chatter_transports: telegram: 'null://null' channel_policy: # 确保所有优先级通道映射到代码中使用的chat/telegram urgent: ['chat/telegram'] high: ['chat/telegram'] medium: ['chat/telegram'] low: ['chat/telegram']
代码中指定了channels: ['chat/telegram'],必须保证测试环境的channel_policy将对应优先级映射到该通道,否则Notifier找不到传输方式。
2. 改用Messenger断言检测异步消息
assertQueuedNotificationCount是针对同步发送的通知设计的,异步消息会被投递到Messenger队列,需要用Messenger的测试断言来检测:
在测试类中引入Symfony\Bundle\FrameworkBundle\Test\MessengerAssertionsTrait,替换原有断言逻辑:
// 检测队列中是否有1条消息 $this->assertMessageCount(1); // 精确匹配Notifier的ChatMessage类 $this->assertQueuedMessageCount(\Symfony\Component\Notifier\Message\ChatMessage::class, 1); // 验证消息内容 $messages = $this->getQueuedMessages(); /** @var \Symfony\Component\Notifier\Message\ChatMessage $message */ $message = $messages[0]; $this->assertEquals('Symfony Notifier', $message->getSubject()); $this->assertEquals('telegram', $message->getTransport());
3. 确认Messenger路由配置
确保测试环境下messenger.yaml的路由规则未被覆盖,Symfony\Component\Notifier\*必须路由到async传输。若测试环境有单独的Messenger配置,需保持与生产环境一致。
问题根源
ChatterInterface直接使用配置的传输通道同步发送,测试环境的null://null传输能被测试断言直接捕获;NotifierInterface依赖message_bus和channel_policy完成消息路由,测试环境缺少这些配置,导致消息无法进入异步队列,或测试无法追踪到消息。
内容的提问来源于stack exchange,提问作者Григорий
相关产品推荐
相关产品推荐

