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

时间:2016-07-21 05:26:01

标签: cakephp phpunit cakephp-3.x

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

// 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没有被加载(它不在加载的行为列表中,因此使用它的tyring函数会给出未知的方法错误)。我尝试将其添加到UsersController的测试用例

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 个答案:

答案 0 :(得分:1)

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

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

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

<强> https://github.com/cakephp/cakephp/blob/3.2.12/src/TestSuite/TestCase.php#L106

因此,在此之前添加到全局事件管理器的所有内容都将丢失。

这是为了避免状态。如果不能完成,那么测试方法A中测试代码添加到全局管理器的可能的监听器仍然会出现在测试方法B中,这当然会导致在那里测试的代码出现问题,比如听众堆叠,导致多次调用它们,调用通常不会被调用的侦听器等。

之后添加全局侦听器作为解决方法

每当我需要gloabl事件时,我会将它们存储在配置值中,并在测试用例中的设置时应用它们,这些都是

<强>自举

$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代码建议的内容。

  2. 实例化一个表类会导致Model.initialize事件被触发,所以即使你之后正确添加了你的监听器,它也永远不会被触发,除非你已经清除了表注册表,所以用户表将在下一次get()调用时新构建。