Доступ к контейнеру запросов (event_dispatcher) в тестовом клиенте - PullRequest
0 голосов
/ 20 февраля 2020

Я создал простой тестовый пример в Symfony. Таким образом, один клиент должен прослушивать событие, которое будет отправлено во время запроса. Но ничего не происходит, потому что запрос имеет собственную область, или я не знаю, почему я не могу получить доступ к диспетчеру в нем.

$this->client = static::createClient();
self::$container = $this->client->getContainer();

$dispatcher = self::$container->get('event_dispatcher');

$dispatcher->addListener('example', function ($event) {
    // Never executed
});

$this->client->request('POST', $endpoint, $this->getNextRequestParameters($i), [$file], $this->requestHeaders);
$this->client->getResponse();

Слушатель никогда не вызывается. Когда я немного отлаживаю, я обнаруживаю, что объект ha sh через spl_object_hash($dispatcher) отличается на самом высоком уровне, чем на уровне request. Таким образом, кажется, что request имеет свой собственный мир и игнорирует все, что находится снаружи.

Но тогда возникает вопрос, как я могу поставить своего слушателя в этот "мир"?

1 Ответ

2 голосов
/ 20 февраля 2020

Я думаю, что частью проблемы является смешение стилей тестирования. У вас есть WebTestCase, который предназначен для очень высокого уровня тестирования (запросы и ответы). На самом деле это не должно заботить внутренние органы, то есть, какие службы или слушатели вызываются. Важно только, чтобы при вводе x (ваш запрос) вы получали вывод y (ваш ответ). Это позволяет гарантировать, что базовая функциональность c, воспринимаемая вашими пользователями, всегда соблюдается, не заботясь о том, как это делается. Делая эти тесты очень гибкими.

Рассматривая контейнер и сервисы, вы переходите на более низкий уровень тестирования, который тестирует взаимосвязанные сервисы. Обычно это делается только в том же процессе по причинам, которые вы уже выяснили. У теста более высокого уровня есть 2 отдельных жизненных цикла, один для самого теста и один для смоделированного веб-запроса к вашему приложению, следовательно, разные идентификаторы объектов.

Решение - либо передать что-то на более высокий уровень, например установив заголовки или изменив вывод, вы можете проверить тело ответа. Вы также можете записать в некоторый файл журнала и проверить журналы до / после запроса на это сообщение.

Другой вариант - переместить весь тест на более низкий уровень, где вам не нужны запросы, и вместо этого работать только с сервисами. Для этого вы можете использовать KernelTestCase (вместо WebTestCase) и вместо звонка createClient() вы звоните bootKernel. Это даст вам доступ к вашему контейнеру, где вы можете изменить EventDispatcher. Вместо отправки запроса вы можете либо напрямую вызвать код, например, отправить событие, если вы хотите только протестировать слушателей, либо вы можете сделать свой контроллер доступным в качестве службы, а затем вручную создать запрос, вызвать действие и затем либо проверить ответ или что-то еще, на что вы хотите заявить. Это может выглядеть примерно так:

public function testActionFiresEvent()
{
    $kernel = static::bootKernel();

    $eventDispatcher = $kernel->getContainer()->get('event_dispatcher');

    // ...

    $request = Request::create();

    // This might not work when the controller
    // You can create a service configuration only used by tests,
    // e.g. "config/services_test.yaml" and provide the controller service there
    $controller = $kernel->getContainer()->get(MyController::class);

    $response = $controller->endpointAction($request);

    // ...Do assertions...
}
...