我通过初始化事件侦听器将一个行为添加到所有模型中。
// src/Event/InitializeEventListener.php
...
class InitializeEventListener implements EventListenerInterface
{
public function implementedEvents()
{
return [
'Model.initialize' => 'initializeEvent'
];
}
public function initializeEvent(Event $event, $data = [], $options = [])
{
$event->subject()->addBehavior('MyBehavior');
}
}
// bootstrap.php
$ieListener = new InitializeEventListener();
EventManager::instance()->on($ieListener);
我有UsersController
和index
操作。如果我输入debug($this->Users->behaviors()->loaded());die;
,我可以看到默认的Timestamp
和加载的MyBehavior
。到目前为止,所有工作都很好,我可以在索引操作中使用MyBehavior
的函数。这是在浏览器中打开页面时。
现在我有了这个测试函数
// tests/TestCase/Controller/UsersControllerTest.php
public function testIndex()
{
$this->get('/users/index');
$this->assertResponseSuccess();
}
然而,当运行测试时,MyBehavior
没有被加载(它不在加载的行为列表中,因此尝试使用它的函数会产生未知的方法错误)。
public function setUp()
{
parent::setUp();
$this->Users = TableRegistry::get('Users');
$eventList = new EventList();
$eventList->add(new Event('Users.initializeEvent'));
$this->Users->eventManager()->setEventList($eventList);
}
但是MyBehavior
同样没有被加载。
谢谢
1条答案
按热度按时间50pmv0ei1#
每个测试一个新的全局事件管理器
问题是CakePHP测试用例在设置时设置了一个新的全局事件管理器示例:
http://github.com/cakephp/cakephp/blob/3.2.12/src/TestSuite/TestCase.php#L106
因此,在该点之前添加到全局事件管理器中的所有内容都将丢失。
这样做是为了避免状态。如果不这样做,那么由测试方法A中的被测代码添加到全局管理器中的可能的侦听器,仍然会出现在测试方法B中,这当然会导致在那里测试的代码出现问题,比如侦听器堆积起来,导致它们被多次调用,被调用的侦听器通常不会被调用,等等。
在较新的CakePHP版本中使用
Application::bootstrap()
从CakePHP 3.3开始,你可以在你的应用程序的
Application
类中使用bootstrap()
方法,不像config/bootstrap.php
文件,它只被包含一次,该方法被调用用于每个集成测试请求。这样,在测试用例分配了一个新的干净事件管理器示例之后,您的全局事件就会被添加。
作为一种解决方法,可以在以后添加全局侦听器
在CakePHP 3.3之前的版本中,每当我需要global事件时,我都会将它们存储在一个配置值中,并在测试用例中的设置时间应用它们,大致如下
引导
测试用例基类
您的代码段未添加任何侦听器
也就是说,您的安装代码片段的问题在于
1.它与监听事件无关,而是与跟踪调度的事件有关。此外,你的应用中可能没有
Users.initializeEvent
事件,至少你的InitializeEventListener
代码是这样建议的。1.示例化一个表类将导致触发
Model.initialize
事件,因此,即使您后来正确地添加了侦听器,它也永远不会被触发,除非您清除了表注册表,以便在下一次get()
调用时重新构造用户表。