Как проверить, что события 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

Другая распространенная проблема возникает из-за выполнения нескольких запросов во время одного и того же сценария, тогда все сообщения, хранящиеся в памяти, будут потеряны. В этом случае я рекомендую использовать транспорт доктрины.

Другие вопросы по тегам