Как проверить, что события Symfony Messenger отправляются в сценарии с несколькими шинами с использованием Behat?
Кажется сложным, и нет много документации по этому поводу (я использую расширение FirendsOfBehat Symfony). Я хочу проверить, Transport
переносит любые события, используя get()
метод, но я не получаю никаких результатов. Такое ощущение, что он не направляет правильный автобус.
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: Отправка сообщения App\EventAdapter с Symfony\Component\Messenger\Transport\InMemoryTransport {"message":"[объект] (App\EventAdapter: {})","class":"App\EventAdapter","sender":"Symfony\Component\Messenger\Transport\InMemoryTransport"} []
2 ответа
Вот актуальный пример для тех, кто натыкается на это, используя, когда также использует
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());
}
}
Я думаю, что проблема в том, что есть два разных контейнера (один для приложения, а другой для изолированного драйвера Mink), и они не передают состояние своих сервисов, поэтому невозможно получить помещенные в очередь сообщения в памяти.
Первое решение, которое приходит мне на ум, - это отказ от использования Mink API и начало использования BrowserKit API (https://github.com/FriendsOfBehat/SymfonyExtension/pull/82).
Второе решение будет использовать эту недавно введенную функцию для доступа к тестируемым службам приложений через контейнер службы драйвера: https://github.com/FriendsOfBehat/SymfonyExtension/pull/116
Другая распространенная проблема возникает из-за выполнения нескольких запросов во время одного и того же сценария, тогда все сообщения, хранящиеся в памяти, будут потеряны. В этом случае я рекомендую использовать транспорт доктрины.