如何测试在内部使用AuthComponent :: user的Model方法

时间:2013-10-02 10:23:32

标签: php unit-testing cakephp mocking cakephp-2.0

我正在使用CakePHP 2.4

我有一个名为Storybook的Model类。

有一个名为createDraft的方法,其代码如下所示:

    public function createDraft($data) {
        $data['Storybook']['author']    = AuthComponent::user('id');

当我使用CakePHP测试编写测试脚本时,我在AuthComponent中实例化用户数据时出现问题。

我的测试脚本如下所示:

<?php
App::uses('Storybook', 'Model');
class StorybookTestCase extends CakeTestCase {

/**
 * Fixtures
 *
 * @var array
 */
    public $fixtures = array(...
    );

/**
 * setUp method
 *
 * @return void
 */
    public function setUp() {
        parent::setUp();
        $this->Storybook    = ClassRegistry::init('Storybook');
...
...


/**
 * GIVEN we have only a title
 * WHEN we call createDraft
 * THEN we have a new draft
 *
 * @return void
 */
     public function testCreateDraftSuccessfully() {    
        // GIVEN only a title
        $data = array('Storybook' => array('title' => 'some title'));
        // WHEN we call the createDraft
        $actualResult = $this->Storybook->createDraft($data);
 ....

在createDraft方法测试失败。

我无法在setUp方法中使用用户数据填写AuthComponent,因为AuthComponent登录方法不是静态的。

请告知。

1 个答案:

答案 0 :(得分:3)

我在谷歌搜索并询问#cakephp IRC频道后想出的步骤:

1)确保您至少使用CakePHP 2.3

2)在AppModel中创建以下受保护的函数:

protected function _getUser($key = null) {
    return AuthComponent::user($key);
}

3)确保在AppModel中实际使用AuthComponent:

//type this just below App::uses('Model', 'Model');
App::uses('AuthComponent', 'Controller/Component');

4)更改Storybook模型以使用_getUser而不是AuthComponent :: user

    public function createDraft($data) {
        $data['Storybook']['author']    = $this->_getUser('id');

5)将以下内容添加到测试方法中,由documentation提供:

public function testCreateDraftSuccessfully() {    

        // MOCK the _getUser method to always return 23 because we always expect that
        $this->Storybook = $this->getMockForModel('Storybook', array('_getUser'));
        $this->Storybook->expects($this->once())
        ->method('_getUser')
        ->will($this->returnValue(23));

    // GIVEN only a title
    $data = array('Storybook' => array('title' => 'some title'));

这将帮助您通过测试。

<强>更新

如果您正在模拟的方法可能会根据不同的参数返回不同的结果,则需要使用另一个公共函数作为模拟方法的回调。

步骤5的替代方案)如果您希望在参数为“id”时始终返回23,则添加以下函数;如果参数为“group_id”,则返回1

public function getUserCallBack($field) {
        if ($field == 'id') {
            return 23;
        }
        if ($field == 'group_id') {
            return 1;
        }
    }

6)将测试方法更改为:

public function testCreateDraftSuccessfully() {    

        // MOCK the _getUser method to always return 23 for _getUser('id') and 1 for _getUser('group_id')
        $this->Storybook = $this->getMockForModel('Storybook', array('_getUser'));
        $this->Storybook->expects($this->once())
        ->method('_getUser')
        ->with($this->logicalOr(
            $this->equalTo('id'),
            $this->equalTo('group_id')
        ))
        ->will($this->returnCallback(array($this, 'getUserCallBack')));

    // GIVEN only a title
    $data = array('Storybook' => array('title' => 'some title'));

Useful list of matchers for PHPunit.例如

$this->once()
$this->never()