如何使用 Behat 测试在多总线场景中调度 Symfony Messenger 事件?
Posted
技术标签:
【中文标题】如何使用 Behat 测试在多总线场景中调度 Symfony Messenger 事件?【英文标题】:How to test that Symfony Messenger events are dispatched in a multi bus scenario using Behat? 【发布时间】:2020-01-03 19:33:53 【问题描述】:似乎很难,并且没有太多关于此的文档(我正在使用 FirendsOfBehat Symfony 扩展)。我想通过使用get()
方法测试Transport
是否携带任何事件,但我没有得到任何结果。感觉好像它没有路由正确的总线。
declare(strict_types=1);
namespace App\Features\BehatContext;
class MessengerContext implements Context
/**
* @var TransportInterface
*/
private $transport;
/**
* MessengerContext constructor.
*
* @param TransportInterface $transport ??? Is this ok
*/
public function __construct(TransportInterface $transport)
// Symfony\Component\Messenger\Transport\InMemoryTransport
$this->transport = $transport;
/**
* THIS IS WHAT DOESN'T WORK
* @Given /^(\d+) Events? "([^"]*)" is dispatched$/
*/
public function eventAEventIsDispatched()
$eventsDispatched = $this->transport->get();
Assert::assertTrue(count($eventsDispatched));
我的packages/messenger.yaml
配置:
framework:
messenger:
default_bus: event.bus
buses:
command.bus:
middleware:
- validation
event.bus:
default_middleware: allow_no_handlers
transports:
sync: 'sync://'
event: 'in-memory:///'
routing:
'App\AddMagazine': sync
'App\MagazineAdded': event
'App\EventAdapter': event
这是调度我的事件的类
declare(strict_types=1);
namespace App\Event\Dispatcher;
class SymfonyEventDispatcher implements ApplicationDomainDispatcherInterface
private $messageBus;
/**
* SymfonyEventDispatcher constructor.
*
* @param MessageBusInterface $sfDispatcher
*/
public function __construct(MessageBusInterface $eventBus)
// messageBus is Symfony\Component\Messenger\TraceableMessageBus
$this->messageBus = $eventBus;
/**
* @param EventInterface $event
*
* @return EventInterface
*/
public function dispatch(EventInterface $event): EventInterface
$eventAdapter = new EventAdapter($event);
$this->messageBus->dispatch(new Envelope($eventAdapter));
return $eventAdapter;
这是我的 service_test.yaml 文件,在运行 Behat 测试时会考虑到该文件:
services:
_defaults:
autowire: true
autoconfigure: true
App\Features\BehatContext\:
resource: '../features/BehatContext/*'
App\Features\BehatContext\MessengerContext:
arguments:
$transport: '@messenger.transport.event'
检查我的日志,我可以看到信使确实发送了事件:
[2019-08-30 14:14:50] messenger.INFO: 使用 Symfony\Component\Messenger\Transport\InMemoryTransport 发送消息 App\EventAdapter "message":"[object] (App\EventAdapter: )","class":"App\EventAdapter","sender":"Symfony\Component\Messenger\Transport\InMemoryTransport" []
【问题讨论】:
【参考方案1】:这是一个最新的例子,任何人在使用MinkContext
时偶然发现这个问题
<?php
declare(strict_types=1);
namespace App\Features\Bootstrap;
use Behat\Behat\Context\Context;
use Behat\Behat\Hook\Scope\BeforeScenarioscope;
use Behat\MinkExtension\Context\MinkContext;
use PHPUnit\Framework\Assert;
use Psr\Container\ContainerInterface;
use Symfony\Component\Messenger\Transport\InMemoryTransport;
/**
* @author Daniel West <daniel@silverback.is>
*/
class MessengerContext implements Context
private ContainerInterface $container;
/**
* @BeforeScenario
*/
public function getContexts(BeforeScenarioScope $scope): void
/** @var MinkContext $mink */
$mink = $scope->getEnvironment()->getContext(MinkContext::class);
$client = $mink->getSession()->getDriver()->getClient();
$container = $client->getContainer();
$this->container = $container->has('test.service_container') ? $container->get('test.service_container') : $container;
/**
* @Then /(\d+) message(?:s)? should have been sent to the transport named (.*)/
*/
public function messaesHaveBeenSentToTheTransport(int $count, string $name): void
/** @var InMemoryTransport $transport */
$transport = $this->container->get(sprintf('messenger.transport.%s', $name));
Assert::assertCount($count, $transport->get());
【讨论】:
【参考方案2】:我认为问题在于有两个不同的容器(一个用于应用程序,另一个用于 Mink 隔离驱动程序),并且它们不共享其服务状态,因此无法获取内存中排队的消息。
我的第一个解决方案是放弃使用 Mink API 并开始使用 BrowserKit API (https://github.com/FriendsOfBehat/SymfonyExtension/pull/82)
第二种解决方案是使用这个最近引入的功能,通过驱动程序的服务容器访问测试的应用程序服务:https://github.com/FriendsOfBehat/SymfonyExtension/pull/116
另一个常见的问题是在同一个场景中发出多个请求,然后存储在内存中的所有消息都会丢失。在这种情况下,我建议使用学说传输。
【讨论】:
以上是关于如何使用 Behat 测试在多总线场景中调度 Symfony Messenger 事件?的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 docker-compose 在 docker 容器中为 Laravel 环境安装 Behat?
如何使用 Behat/Mink 切换到动态命名的 iframe