2017-06-30 5 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; 
    } 
} 

このメソッドを繰り返し呼び出すことで、クエリが1回実行されることをテストで確認するにはどうすればよいですか?キャッシュ変数を使用するメソッドをテストするには?

好ましくは、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つのアサーションを持っている必要があり、 1つは期待されるメソッド呼び出し用、もう1つは返された値用です。このテストはアクティブレコードをバイパスし、getIds()メソッドが期待通りに機能することを保証します。これにアプローチするもう1つの方法は、あなたの質問へのコメントで述べたように、(テスト)データベースからデータをフェッチすることでデータベースのやりとりを実際にテストする機能テストを使用することです。明らかに、これは、データベース接続を有し、テストデータを取り出すことを必要とするためである。これまでに設定されていたフィクスチャでは、もう少し作業が多く、テストは遅くなります。あなたのプロジェクトの大きさにもよるが、それは問題ではないかもしれないし、Active Record実装のロジックをより快適にテストできるように感じるかもしれない。

関連する問題