如何在多总线场景下用Behat测试Symfony Messenger事件分发?
看起来你遇到的问题核心在于Symfony的InMemoryTransport的get()方法并不是获取已发送的消息——这个方法是用来从队列中取出待处理的消息,而你的事件通过总线发送后,其实是存在Transport的sentMessages私有属性里的,所以调用get()自然拿不到内容。
下面是一步步的解决方案:
1. 自定义测试用的InMemoryTransport
原生的InMemoryTransport没有暴露已发送消息的接口,我们可以创建一个自定义子类来封装这个功能:
// src/Test/Transport/InMemoryTransport.php declare(strict_types=1); namespace App\Test\Transport; use Symfony\Component\Messenger\Transport\InMemory\InMemoryTransport as BaseInMemoryTransport; class InMemoryTransport extends BaseInMemoryTransport { // 获取所有已发送的消息 public function getSentMessages(): array { return $this->sentMessages; } // 清空已发送消息(避免测试场景间的数据污染) public function clearSentMessages(): void { $this->sentMessages = []; } }
2. 配置测试环境使用自定义Transport
修改config/packages/test/messenger.yaml,让event传输使用我们自定义的类:
framework: messenger: default_bus: event.bus buses: command.bus: middleware: - validation event.bus: default_middleware: allow_no_handlers transports: sync: 'sync://' event: dsn: 'in-memory:///' class: App\Test\Transport\InMemoryTransport # 指定自定义类 routing: 'App\AddMagazine': sync 'App\MagazineAdded': event 'App\EventAdapter': event
3. 修复MessengerContext的测试方法
更新你的MessengerContext,使用自定义Transport的方法来获取已发送消息,同时修正步骤参数的接收问题:
// src/Features/BehatContext/MessengerContext.php declare(strict_types=1); namespace App\Features\BehatContext; use App\Test\Transport\InMemoryTransport; use Assert\Assert; use Behat\Behat\Context\Context; use Behat\Behat\Hook\Scope\BeforeScenarioScope; use Symfony\Component\Messenger\Envelope; class MessengerContext implements Context { /** * @var InMemoryTransport */ private $transport; public function __construct(InMemoryTransport $transport) { $this->transport = $transport; } // 每个场景前清空已发送消息,避免数据污染 /** * @BeforeScenario */ public function clearSentMessages(BeforeScenarioScope $scope): void { $this->transport->clearSentMessages(); } /** * @Given /^(\d+) Events? "([^"]*)" is dispatched$/ */ public function assertEventIsDispatched(int $expectedCount, string $eventClassName): void { $sentMessages = $this->transport->getSentMessages(); // 过滤出匹配的事件(因为你用了EventAdapter包装,需要取出内部的Event对象) $matchingEvents = array_filter($sentMessages, function (Envelope $envelope) use ($eventClassName) { $message = $envelope->getMessage(); return $message instanceof \App\EventAdapter && $message->getEvent() instanceof $eventClassName; }); Assert::assertEquals( $expectedCount, count($matchingEvents), sprintf("Expected %d instances of %s to be dispatched, found %d", $expectedCount, $eventClassName, count($matchingEvents)) ); } }
额外检查点
- 从你的日志来看,
send_message中间件已经正常工作(消息已发送到InMemoryTransport),所以不需要额外配置总线中间件; - 可选优化:步骤正则可以改成
/^(\d+) Events? "([^"]*)" (is|are) dispatched$/,让语法更严谨,不影响功能。
这样修改后,你就能正确获取到已发送的事件,完成Behat测试的断言了。
内容的提问来源于stack exchange,提问作者db306
相关产品推荐
相关产品推荐

