【问题标题】:CakePHP 2.1 - Unit Testing Controllers $this->view and $this->contents equals nullCakePHP 2.1 - 单元测试控制器 $this->view 和 $this->contents 等于 null
【发布时间】:2012-05-25 05:11:31
【问题描述】:

切换到 cakephp 2.1 并开始学习单元测试...

当我ArticlesControllerTestCase::testView()

然后运行

$this->testAction('articles/view/1'); 
debug($this->view); 
debug($this->contents); 
die;

$this->view and $this->contents 都等于 null

我已经清空了 beforeFilter 调用和 beforeRender 调用以尝试限制它...

我注意到在控制器操作中,如果我在方法的末尾设置$this->render('view');,我会得到$this->view = '它应该是什么',但$this->contents = '到同样的事情并且做不包含布局

知道为什么会这样吗?

class ArticlesController extends MastersController {

    /*
     * Name
     */
    public $name = 'Articles';

    /*
     * Publicly Accessible Methods
     */
    public $allowed = array('view', 'index', 'category', 'news');


    /*
     * Default Search Params
     */
    public $presetVars = array(
        array('field' => 'title', 'type' => 'value'),
        array('field' => 'category_id', 'type' => 'value'),
        array('field' => 'status_id', 'type' => 'value'),           
    );

    /*
     * Admin Menu Options
     */
    public $adminMenu = array('index'=>array('Category'));

    /**
     * Before Filter Callback
     * (non-PHPdoc)
     * @see controllers/MastersController::beforeFilter()
     * @return void
     */
    public function beforeFilter(){
        parent::beforeFilter();
        $categories = $this->Article->Category->find('class', array('article', 'conditions'=>array('not'=>array('Category.name'=>'Content'))));
        $this->set(compact('categories'));
    }

    /**
     * View
     * @param $id
     * @see controllers/MastersController::_view()
     * @return void
     */
    public function view($id){
        parent::_view($id);
        $articleTitle = $this->Article->findField($id,'title');
        $recentNews = $this->Article->find('recentNews');
        $this->set('title_for_layout', $articleTitle);
        $this->set(compact('recentNews'));
    }
};

class MastersController extends AppController {

    /*
     * Name
     */
    public $name = 'Masters'; # expected to be overridden

    /**
     * View
     * Default view method for all controllers
     * Provides an individual record based on the record id
     * @param int $id: model id
     * @return void
     */
    protected function _view($id){
        $this->Redirect->idEmpty($id, array('action'=>'index'));
        ${Inflector::singularize($this->request->params['controller'])} = $this->{$this->modelClass}->find('record', array($id));
        ${Inflector::variable(Inflector::singularize($this->request->params['controller']))} = ${Inflector::singularize($this->request->params['controller'])};

        if(empty(${Inflector::singularize($this->request->params['controller'])})){
            return $this->Redirect->flashWarning('Invalid Id.', $this->referer());
        }       
        $this->set(compact(Inflector::singularize($this->request->params['controller']), Inflector::variable(Inflector::singularize($this->request->params['controller']))));
    }
}


class ArticlesControllerTestCase extends ControllerTestCase {

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

    /**
     * Set Up
     *
     * @return void
     */
    public function setUp() {
        parent::setUp();
        $this->Articles = new TestArticlesController();
        $this->Articles->constructClasses();
    }

    /**
     * Tear Down
     *
     * @return void
     */
    public function tearDown() {
        unset($this->Articles);

        parent::tearDown();
    }

    /**
     * Test View
     *
     * @return void
     */
    public function testView() {
        $this->testAction('articles/view/1');
        debug($this->view); die;
    }
}


class ArticleFixture extends CakeTestFixture {

    /**
     * Fields
     *
     * @var array
     */
    public $fields = array(
        'id' => array('type' => 'integer', 'null' => false, 'default' => NULL, 'key' => 'primary'),
        'slug' => array('type' => 'string', 'null' => true, 'default' => NULL, 'length' => 120, 'collate' => 'latin1_swedish_ci', 'charset' => 'latin1'),
        'title' => array('type' => 'string', 'null' => false, 'default' => NULL, 'length' => 100, 'collate' => 'latin1_swedish_ci', 'charset' => 'latin1'),
        'body' => array('type' => 'text', 'null' => false, 'default' => NULL, 'collate' => 'latin1_swedish_ci', 'charset' => 'latin1'),
        'created' => array('type' => 'datetime', 'null' => false, 'default' => NULL),
        'modified' => array('type' => 'datetime', 'null' => false, 'default' => NULL),
        'status_id' => array('type' => 'integer', 'null' => false, 'default' => NULL),
        'category_id' => array('type' => 'integer', 'null' => false, 'default' => NULL),
        'indexes' => array('PRIMARY' => array('column' => 'id', 'unique' => 1)),
        'tableParameters' => array('charset' => 'utf8', 'collate' => 'utf8_general_ci', 'engine' => 'InnoDB')
    );

    /**
     * Records
     *
     * @var array
     */
    public $records = array(
        array(
            'id' => '1',
            'slug' => NULL,
            'title' => 'Test Article #1 without slug - published',
            'body' => '<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.</p><p>Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>',
            'created' => '2011-02-15 21:14:03',
            'modified' => '2011-02-15 21:14:03',
            'status_id' => '1',
            'category_id' => '5'
        ),
         );
}

【问题讨论】:

  • $this 不是指您的控制器,而是指您的测试用例。

标签: cakephp phpunit cakephp-2.1


【解决方案1】:

如果您被重定向,例如,如果会话数据不符合预期,某些身份验证代码会重定向到登录页面,则可能会发生这种情况。如果您没有在测试中设置所需的环境,您将被重定向。您可以通过检查$this-&gt;headers 的值来检查这一点:

debug("Headers: " . print_r($this->headers));

如果您将其放入测试中并看到类似 array('Location' =&gt; 'your_login_page') 的内容,请确保您的测试环境包含使您的身份验证系统(或任何其他可能插入重定向)满意所需的一切。

【讨论】:

    【解决方案2】:

    您需要捕获 $this->testAction 的结果并指定要返回的内容(http://book.cakephp.org/2.0/en/development/testing.html#testing-controllers

    例如

    $result = $this->testAction('articles/view/1', array('return'=>'content'));
    
    debug($result);
    

    【讨论】:

    • 我遇到了这个问题。除非articles/view/1 接受发布请求,否则提供“return”仍将导致空值。必须在 testAction() 中提供 method=get 选项
    【解决方案3】:

    如果您打算执行单元测试,您应该认真考虑测试每个单独的单元。话虽这么说,PHPUnit 在集成到 CakePHP 时相当健壮,可以提供您需要的东西,例如数据和方法模拟。

    当我编写单元测试时,它看起来有点像这样:

    function testSomeTestCaseWithDescriptiveMethodName(){
        $this->testAction("controller/action/arguments");
        $this->assertEqual([some value or data set], $this->vars["key"];
    }
    

    这将使您无需进行集成测试(包括视图、数据库访问等)就可以针对创建的值进行测试。

    我希望这会有所帮助。 :)

    【讨论】:

      【解决方案4】:

      我想我知道导致问题的原因。您需要提供 testAction() 的方法。

      $this->testAction('articles/view/1', array('method'=>'get')); 
      debug($this->view); //should output the view
      debug($this->contents);  //should output the contents
      

      恕我直言,文档 (http://book.cakephp.org/2.0/en/development/testing.html#testing-controllers) 看起来默认是 GET。默认值实际上是 POST - 因此“发布”到文章/视图/1 将一无所获。

      【讨论】:

      • 也尝试调试($this->headers) - 检查你是否从页面重定向
      • 仍然设置为空...如果我设置 $this->render('view');在控制器操作中,然后 $this->view/$this->contents 设置正确。但是我不需要这样做.. debug($this->headers) 仍然是一个空数组。我必须尽快解决这个问题,在这个项目上落后了。
      • 如果您没有被重定向,$this->headers 将为空。如果你有 $this->view / $this->contents 那么你应该对那些恕我直言做断言....问别人...
      猜你喜欢
      • 2012-06-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-02-27
      • 2012-05-25
      • 1970-01-01
      • 1970-01-01
      • 2013-06-14
      相关资源
      最近更新 更多