我在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
似乎有一个自己的世界,忽略了外面的一切。
但问题是,我如何才能让我的听众进入这个"世界"?
我认为问题的一部分是测试风格的混合。您有一个WebTestCase,它旨在进行非常高级别的测试(请求和响应(。它不应该真正关心内部,即调用哪些服务或侦听器。它只关心给定的输入x(您的请求(,您将得到输出y(您的响应(。这可以确保用户所感知的基本功能始终得到满足,而无需关心如何实现。使这些测试非常灵活。
通过查看容器和服务,您将进入一个较低级别的测试,测试互连的服务。由于您已经发现的原因,这通常只在同一过程中完成。更高级别的测试有两个独立的生命周期,一个用于测试本身,另一个用于对应用程序的模拟web请求,因此有不同的对象id。
解决方案是将某些内容发送到更高级别,例如通过设置标头或更改输出,这样您就可以检查响应主体。您还可以写入一些日志文件,并在请求该消息之前/之后检查日志。
另一种选择是将整个测试转移到一个较低的级别,在那里您不需要请求,而只使用服务。为此,您可以使用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...
}