Cakephp 3 -在控制器单元测试期间未加载行为

tcbh2hod  于 2022-11-11  发布在  PHP
关注(0)|答案(1)|浏览(158)

我通过初始化事件侦听器将一个行为添加到所有模型中。

// 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);

我有UsersControllerindex操作。如果我输入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同样没有被加载。
谢谢

50pmv0ei

50pmv0ei1#

每个测试一个新的全局事件管理器

问题是CakePHP测试用例在设置时设置了一个新的全局事件管理器示例:

public function setUp()
{
    // ...
    EventManager::instance(new EventManager());
}

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事件时,我都会将它们存储在一个配置值中,并在测试用例中的设置时间应用它们,大致如下

引导

$globalListeners = [
    new SomeListener(),
    new AnotherListener(),
];
Configure::write('App.globalListeners', $globalListeners);
foreach ($globalListeners as $listener) {
    EventManager::instance()->on($listener);
}

测试用例基类

public function setUp()
{
    parent::setUp();

    foreach (Configure::read('App.globalListeners') as $listener) {
        EventManager::instance()->on($listener);
    }
}

您的代码段未添加任何侦听器

也就是说,您的安装代码片段的问题在于
1.它与监听事件无关,而是与跟踪调度的事件有关。此外,你的应用中可能没有Users.initializeEvent事件,至少你的InitializeEventListener代码是这样建议的。
1.示例化一个表类将导致触发Model.initialize事件,因此,即使您后来正确地添加了侦听器,它也永远不会被触发,除非您清除了表注册表,以便在下一次get()调用时重新构造用户表。

相关问题