2013-05-08 78 views
4

現狀

控制器代碼CakePHP的控制器測試:嘲諷驗證組件

<?php 
App::uses('AppController', 'Controller'); 

class PostsController extends AppController { 

    public function isAuthorized() { 
     return true; 
    } 

    public function edit($id = null) { 
     $this->autoRender = false; 

     if (!$this->Post->exists($id)) { 
      throw new NotFoundException(__('Invalid post')); 
     } 

     if ($this->Post->find('first', array(
      'conditions' => array(
       'Post.id' => $id, 
       'Post.user_id' => $this->Auth->user('id') 
      ) 
     ))) { 
      echo 'Username: ' . $this->Auth->user('username') . '<br>'; 
      echo 'Created: ' . $this->Auth->user('created') . '<br>'; 
      echo 'Modified: ' . $this->Auth->user('modified') . '<br>'; 
      echo 'All:'; 
      pr($this->Auth->user()); 
      echo 'Modified: ' . $this->Auth->user('modified') . '<br>'; 
     } else { 
      echo 'Unauthorized.'; 
     } 
    } 
} 

從瀏覽器

Username: admin 
Created: 2013-05-08 00:00:00 
Modified: 2013-05-08 00:00:00 
All: 

Array 
(
    [id] => 1 
    [username] => admin 
    [created] => 2013-05-08 00:00:00 
    [modified] => 2013-05-08 00:00:00 
) 

Modified: 2013-05-08 00:00:00 

測試代碼

0輸出
<?php 
App::uses('PostsController', 'Controller'); 

class PostsControllerTest extends ControllerTestCase { 

    public $fixtures = array(
     'app.post', 
     'app.user' 
    ); 

    public function testEdit() { 
     $this->Controller = $this->generate('Posts', array(
      'components' => array(
       'Auth' => array('user') 
      ) 
     )); 

     $this->Controller->Auth->staticExpects($this->at(0))->method('user')->with('id')->will($this->returnValue(1)); 
     $this->Controller->Auth->staticExpects($this->at(1))->method('user')->with('username')->will($this->returnValue('admin')); 
     $this->Controller->Auth->staticExpects($this->at(2))->method('user')->with('created')->will($this->returnValue('2013-05-08 00:00:00')); 
     $this->Controller->Auth->staticExpects($this->at(3))->method('user')->with('modified')->will($this->returnValue('2013-05-08 00:00:00')); 
     $this->Controller->Auth->staticExpects($this->at(4))->method('user')->will($this->returnValue(array(
      'id' => 1, 
      'username' => 'admin', 
      'created' => '2013-05-08 00:00:00', 
      'modified' => '2013-05-08 00:00:00' 
     ))); 

     $this->testAction('/posts/edit/1', array('method' => 'get')); 
    } 
} 

從測試

Username: admin 
Created: 2013-05-08 00:00:00 
Modified: 2013-05-08 00:00:00 
All: 

Array 
(
    [id] => 1 
    [username] => admin 
    [created] => 2013-05-08 00:00:00 
    [modified] => 2013-05-08 00:00:00 
) 

Modified: 

輸出的問題

實際上有三個問題在這裏:

  1. 測試代碼是很重複。
  2. 測試輸出中的第二個「修改」行是空白的。它在 應該是「2013-05-08 00:00:00」就像在瀏覽器的輸出。
  3. 如果我要修改控制器代碼,所述echo ING「用戶名」和「創建」之間增加一個線,所述echo 'Email: ' . $this->Auth->user('email') . '<br>';(只是舉例),則測試將失敗,此錯誤:Expectation failed for method name is equal to <string:user> when invoked at sequence index 2。這是有道理的,因爲$this->at(1)不再是真的。

我的問題

我如何的方式,(1)不重複嘲笑驗證組件,(2)使測試輸出同樣的事情瀏覽器,和(3)允許我可以在任何地方添加$this->Auth->user('foo')代碼而不會破壞測試?

回答

8

在我回答這個問題我不得不承認,我沒有使用CakePHP的框架的經驗。不過,我在PHPUnit和Symfony框架結合使用方面擁有相當豐富的經驗,並遇到類似的問題。爲了解決你的觀點:

  1. 見我的回答3點

  2. 這樣做的原因是,你需要一個額外的...->staticExpects($this->at(5))...聲明涵蓋6日呼籲Auth->用戶()。這些語句沒有定義任何調用Auth-> user()與指定值的返回值。它們定義例如對Auth對象的第二次調用必須通過參數'username'給方法user(),在這種情況下'admin'將被返回。但是,如果你在下一點中採用這種方法,這應該不再是一個問題。

  3. 我假設你在這裏試圖達到的目的是獨立於Auth組件測試你的控制器(因爲坦率地說,測試一個控制器在一個控制器上進行一系列getter調用是沒有意義的用戶對象)。在這種情況下,模擬對象被設置爲存根以始終返回一組特定的結果,而不是期望特定參數系列的調用(See PHP Manual entry on stubs)。這個可能是,只需在代碼中用'$ this-> any()'替換'$ this-> at(x)'即可。但是,雖然這會否定添加我在第2點中提到的額外行的需要,但您仍然有重複。下面的代碼之前編寫測試的TDD方式,我建議如下:以任意順序

    public function testEdit() { 
        $this->Controller = $this->generate('Posts', array(
         'components' => array(
          'Auth' => array('user') 
         ) 
        )); 
         $this->Controller->Auth 
          ->staticExpects($this->any()) 
          ->method('user') 
          ->will($this->returnValue(array(
           'id' => 1, 
           'username' => 'admin', 
           'created' => '2013-05-08 00:00:00', 
           'modified' => '2013-05-08 00:00:00', 
           'email' => '[email protected]', 
          ))); 
    
        $this->testAction('/posts/edit/1', array('method' => 'get')); 
    } 
    

這將使你想獲得用戶控制器進行更新,以使盡可能多地調用屬性如果它們已經被模擬對象返回,則返回。您的模擬對象可以被寫入以返回所有用戶屬性(或者可能全部可能與該控制器相關),而不管控制器是否以及多頻繁地檢索它們。 (注意在你的具體例子中,如果你的模擬包含'email',控制器中的pr()語句將輸出與測試結果不同的結果,但我假設你不希望能夠向記錄添加新屬性而不必更新您的測試)。

編寫測試這種方式意味着你的控制器編輯功能將需要是這樣的 - 一個更容易測試版本:

$this->autoRender = false; 

if (!$this->Post->exists($id)) { 
    throw new NotFoundException(__('Invalid post')); 
} 

$user = $this->Auth->user(); 

if ($this->Post->find('first', array(
    'conditions' => array(
     'Post.id' => $id, 
     'Post.user_id' => Hash::get($user, 'id') 
    ) 
))) { 
    echo 'Username: ' . Hash::get($user, 'username') . '<br>'; 
    echo 'Created: ' . Hash::get($user, 'created') . '<br>'; 
    echo 'Modified: ' . Hash::get($user, 'modified') . '<br>'; 
    echo 'All:'; 
    pr($user); 
    echo 'Modified: ' . Hash::get($user, 'modified') . '<br>'; 
} else { 
    echo 'Unauthorized.'; 
} 

據我所知,哈希::得到($紀錄,$ key)是從記錄中檢索屬性的正確CakePHP方法,儘管使用這裏的簡單屬性我假設用戶[$ key]也可以正常工作。