0

我在 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();

永远不会调用侦听器。当我稍微调试一下时,我发现对象哈希通过spl_object_hash($dispatcher)在最高级别上与在request级别内不同。所以似乎request有一个自己的世界,而忽略了外面的一切。

但接下来的问题是如何让我的听众进入这个“世界”?

4

1 回答 1

2

我认为问题的一部分是测试风格的混合。您有一个 WebTestCase 用于非常高水平的测试(请求和响应)。它不应该真正关心内部,即调用哪些服务或侦听器。它只关心给定输入 x(您的请求),您将获得输出 y(您的响应)。这样可以确保始终满足用户感知的基本功能,而无需关心它是如何完成的。使这些测试非常灵活。

通过查看容器和服务,您将进入较低级别的测试,即测试互连的服务。出于您已经发现的原因,这通常仅在同一过程中完成。更高级别的测试有 2 个独立的生命周期,一个用于测试本身,一个用于对应用程序的模拟 Web 请求,因此有不同的对象 ID。

解决方案是向更高级别发出某些内容,例如通过设置标头或更改输出,以便您可以检查响应正文。您还可以写入一些日志文件并在请求该消息之前/之后检查日志。

另一种选择是将整个测试移到不需要请求的较低级别,而只使用服务。为此,您可以使用KernelTestCase( 而不是WebTestCase) 而不是打电话给createClient()您 call 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...
}
于 2020-02-20T07:01:04.887 回答