2017-06-30 32 views
0
<?php 

use yii\db\ActiveRecord; 

class Model extends ActiveRecord 
{ 
    protected static $ids = []; 

    public static function getIds() 
    { 
     if (empty(static::$ids)) { 
      static::$ids = static::find()->select('id')->column(); 
     } 

     return static::$ids; 
    } 
} 

如何使用測試來確保通過重複調用此方法執行一次查詢?如何測試使用緩存變量的方法?

最好使用codeception或phpunit。

+0

每當您重複使用模型時,都會回滾到默認值? – Yerke

回答

3

測試不僅僅是一種確保代碼正常工作的方式,它們還有助於識別代碼異味。在你的情況下寫一個測試很難,因爲你使用靜態方法。

曾經有一個staticExpects方法,但很久以前在phpunit中已棄用,所以這不是真的可行。使此代碼可測試的最佳方法是刪除static關鍵字。這對getIds()很容易,但由於靜態find()由第三方(yii的ActiveRecord)定義,所以您無法真正刪除它。相反,你可以用非靜態方法來包裝它。通過觸及這些包裝第三方代碼的小方法,這給了您將來可以從Active Record移動到Doctrine等其他實現的好處。

一旦你這樣做,你可以創建模型的部分模擬,以確保該方法被稱爲:

class Model extends ActiveRecord 
{ 
    private $ids; 

    protected function findIds() 
    { 
     return static::find()->select('id')->column(); 
    } 

    public function getIds() 
    { 
     if (empty($this->ids)) { 
      $this->ids = $this->findIds() 
     } 

     return $this->ids; 
    } 
} 

,並在您的測試:

public function testFindIdsIsCalledWhenGetterIsNotInitialized() 
{ 
    $model = $this->getMockBuilder(Model::class) 
     ->setMethods(['findIds']) 
     ->getMock(); 
    $model->expects($this->once()) 
     ->method('findIds') 
     ->will($this->returnValue([1, 2, 3])); 

    $ids = $model->getIds(); 

    $this->assertEquals([1, 2, 3], $ids); 
} 

這應該有2種說法,一個用於預期的方法調用,另一個用於返回的值。此測試繞過活動記錄,只確保您的getIds()方法按預期工作。正如您的問題的評論中提到的,另一種方法是使用功能測試,通過從(測試)數據庫中提取數據來實際測試數據庫交互。顯然,由於這需要數據庫連接並檢索測試數據,例如從一些以前設置的燈具,這是一個更多的工作,測試會更慢。取決於你的項目有多大,這可能不是問題,你也可以更好地測試Active Record實現中的邏輯。