Mocking an authed user in CakePHP

£可爱£侵袭症+ 提交于 2019-12-23 06:16:09

问题


I am writing a CakePHP Unit Test for one of my Controllers. The Controller has several calls to the AuthComponent::user() method, to read data of the currently logged in user. There are 3 usages:

  • AuthComponent::user() (no params, fetches the entire array)
  • AuthComponent::user('id') (fetches the user id)
  • AuthComponent::user('name') (fetches the username)

I have tried two ways of mocking the AuthComponent in my test:

// Mock the Controller and the Components
$this->controller = $this->generate('Accounts', array(
    'components' => array(
        'Session', 'Auth' => array('user'), 'Acl'
    )
));

// Method 1, write the entire user array
$this->controller->Auth->staticExpects($this->any())->method('user')
    ->will($this->returnValue(array(
        'id' => 2,
        'username' => 'admin',
        'group_id' => 1
    )));

// Method 2, specifically mock the AuthComponent::user('id') method
$this->controller->Auth->staticExpects($this->any())->method('user')
    ->with('id')
    ->will($this->returnValue(2));

These methods do not work for me, though. Method 1 doesn't appear to do anything at all, a save operation in my controller that uses the currently logged in user's id returns null, so the value is not properly set/obtained.

Method 2 seems to work, but is too broad, it also tries to bind itself to the AuthComponent::user() call (the one without params) and it fails with the error:

Expectation failed for method name is equal to when invoked zero or more times Parameter 0 for invocation AuthComponent::user(null) does not match expected value. Failed asserting that null matches expected 'id'.

How can I get proper mocks for the AuthComponent so all the fields/variables can be obtained?


回答1:


This is how I do it. Note, in this code, I'm using 'Employee' as my user model, but it should be easy to change.

I have an AppControllerTest.php superclass, which returns a callback for the 'user' method. The callback handles the case with and without params. The _generateMockWithAuthUserId is what you're after - but read it all. There's a couple of other things worth taking note of, like the testPlaceholder. Here's my whole class:

<?php
App::uses('Employee', 'Model');

/**
 * EmployeeNotesController Test Case
 * Holds common Fixture ID's and mocks for controllers
 */
class AppControllerTest extends ControllerTestCase {

    public $authUserId;

    public $authUser;

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

/**
 * tearDown method
 *
 * @return void
 */
    public function tearDown() {
        unset($this->Employee);
        parent::tearDown();
    }

    public function testPlaceholder() {
        // This just here so we don't get "Failed - no tests found in class AppControllerTest"
        $this->assertTrue(true);
    }

    protected function _generateMockWithAuthUserId($contollerName, $employeeId) {
        $this->authUserId = $employeeId;
        $this->authUser = $this->Employee->findById($this->authUserId);
        $this->controller = $this->generate($contollerName, array(
            'methods' => array(
                '_tryRememberMeLogin',
                '_checkSignUpProgress'
            ),
            'components' => array(
                'Auth' => array(
                    'user',
                    'loggedIn',
                ),
                'Security' => array(
                    '_validateCsrf',
                ),
                'Session',
            )
        ));

        $this->controller->Auth
            ->expects($this->any())
            ->method('loggedIn')
            ->will($this->returnValue(true));

        $this->controller->Auth
            ->staticExpects($this->any())
            ->method('user')
            ->will($this->returnCallback(array($this, 'authUserCallback')));
    }

    public function authUserCallback($param) {
        if (empty($param)) {
            return $this->authUser['Employee'];
        } else {
            return $this->authUser['Employee'][$param];
        }
    }
}

Then, my controller test cases inherit from that class:

require_once dirname(__FILE__) . DS . 'AppControllerTest.php';
class EmployeeNotesControllerTestCase extends AppControllerTest {
    // Tests go here

And when you want to mock the auth component in a test, you call

$this->_generateMockWithAuthUserId('EmployeeNotes', $authUserId);

Where 'EmployeeNotes' would be the name of your controller, and $authUserId the ID of a user in the test database.



来源:https://stackoverflow.com/questions/19455540/mocking-an-authed-user-in-cakephp

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!