2016-04-12 8 views
6

私はbootable model traitを使用して、私の特性を使ってモデルの特定のイベントを登録しています。しかし、私は、その形質を使用しているモデルをモックしようとする問題にぶつかってきました。具体的には、モデルのMockeryバージョンがインスタンス化されると、ブートコードはbootMyTraitメソッドを持つ必要があることに同意しますが、呼び出すときにそれを見つけることはできません。Laravelブータブルモデルの特性を模擬した問題

Sample Repositoryを再生するコマンドがあります。一例として、

は、ここに形質である:

namespace App; 
trait MyTrait 
{ 
    public static function bootMyTrait() 
    { 
     print("Booting MyTrait\n"); 
    } 
} 

そして、それを使用したモデル:モデルをインスタンス化

namespace App; 
use Illuminate\Database\Eloquent\Model; 
class MyModel extends Model 
{ 
    use MyTrait; 
} 

は定期的に正常に動作します。これは望ましい出力を示します:

$model = new MyModel(); 

しかし、このモデルを模擬しようとすると協力しません。この:私もモック、いくつかの異なる方法を作成しようとしました

PHPUnit 5.1.0 by Sebastian Bergmann and contributors. 

E                 1/1 (100%) 
Testing that class: Mock_MyModel_9ee820db has method: bootMyTrait because of Trait: App\MyTrait 
Class: Mock_MyModel_9ee820db has method: bootMyTrait 
Class: Mock_MyModel_9ee820db failed calling bootMyTrait 


Time: 129 ms, Memory: 18.00Mb 

There was 1 error: 

1) ExampleTest::testTraitBooting 
PHPUnit_Framework_MockObject_BadMethodCallException: 

mock-bootable-laravel-model-trait/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php:326 
mock-bootable-laravel-model-trait/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php:309 
mock-bootable-laravel-model-trait/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php:296 
mock-bootable-laravel-model-trait/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php:277 
mock-bootable-laravel-model-trait/tests/ExampleTest.php:16 

use Illuminate\Foundation\Testing\WithoutMiddleware; 
use Illuminate\Foundation\Testing\DatabaseMigrations; 
use Illuminate\Foundation\Testing\DatabaseTransactions; 


    class ExampleTest extends TestCase 
    { 
     /** 
     * A basic functional test example. 
     * 
     * @return void 
     */ 
     public function testTraitBooting() 
     { 
      $model = $this->getMock('App\MyModel'); 
     } 
    } 


Fails. Adding some debugging to Eloquent: 


    /** 
    * Boot all of the bootable traits on the model. 
    * 
    * @return void 
    */ 
    protected static function bootTraits() 
    { 
     $class = static::class; 

     foreach (class_uses_recursive($class) as $trait) { 
      print("\nTesting that class: $class has method: " . $method = 'boot'.class_basename($trait) . " because of Trait: $trait\n"); 
      if (method_exists($class, $method = 'boot'.class_basename($trait))) { 
       print("Class: $class has method: $method \n"); 
       try { 
        forward_static_call([$class, $method]); 
       } catch (\PHPUnit_Framework_MockObject_BadMethodCallException $e) { 
        print("Class: $class failed calling $method\n"); 
        throw $e; 
       } 
      } 
     } 
    } 

は私たちにこの障害を与えます。一例として、DatabaseSoftDeletingTraitTestを使用する:

PHPUnit 5.1.0 by Sebastian Bergmann and contributors. 

E                 1/1 (100%) 

Time: 149 ms, Memory: 19.25Mb 

There was 1 error: 

1) ExampleTest::testTraitBooting 
Mockery\Exception\InvalidCountException: Method bootMyTrait() from Mockery_0_App_MyModel should be called 
exactly 1 times but called 0 times. 

mock-bootable-laravel-model-trait/vendor/mockery/mockery/library/Mockery/CountValidator/Exact.php:37 
mock-bootable-laravel-model-trait/vendor/mockery/mockery/library/Mockery/Expectation.php:271 
mock-bootable-laravel-model-trait/vendor/mockery/mockery/library/Mockery/ExpectationDirector.php:120 
mock-bootable-laravel-model-trait/vendor/mockery/mockery/library/Mockery/Container.php:297 
mock-bootable-laravel-model-trait/vendor/mockery/mockery/library/Mockery/Container.php:282 
mock-bootable-laravel-model-trait/vendor/mockery/mockery/library/Mockery.php:142 
mock-bootable-laravel-model-trait/vendor/laravel/framework/src/Illuminate/Foundation/Testing/TestCase.php:122 

だから、私は私がのServiceProviderの起動方法でやっているコードを移動することができますが、その後I:ここ

use Illuminate\Foundation\Testing\WithoutMiddleware; 
use Illuminate\Foundation\Testing\DatabaseMigrations; 
use Illuminate\Foundation\Testing\DatabaseTransactions; 
use Mockery as m; 

class ExampleTest extends TestCase 
{ 
    /** 
    * A basic functional test example. 
    * 
    * @return void 
    */ 
    public function testTraitBooting() 
    { 
     $mock = m::mock('App\MyModel'); 
     $mock->shouldReceive('bootMyTrait')->once(); 
    } 
} 

しかしを、bootMyTraitが呼び出されることはありませんその形質を使用する各モデルを登録する必要があります。これは汚れていると感じ、ブート方法を使用するのが適切だと思われます。だから、私はバグを犯したと思うか、または形質使用モデルを誤って偽っていると思います。私はgetMockForTraitを見てきましたが、私はEloquent(特性のメソッドのいくつかは雄弁なメソッドを呼び出す)の模擬インスタンスを必要とします

私が逃した何かを見た場合(または私は完全に間違った方法に近づいている場合) 、非常にいくつかのテストの後

答えて

2

を高く評価し、私はそのような方法は、それをテストするのに十分だろうと信じて:

$mock = m::mock('App\MyModel')->makePartial(); 
$mock->shouldReceive('bootMyTrait')->once(); 
$mock->__construct(); 

説明:

  1. $mock = m::mock('App\MyModel')->makePartial();

    モックを作成しますが、デフォルトのクラスコンストラクタやその他のメソッドを使用したいので部分的にします。我々はbootMyTrait方法が正確に1時間

  2. を実行しているかどうかを確認したい - それは我々が上書きされることはありませんすべてのメソッドは、これは明らかであるオリジナル App\MyModelクラス

  3. $mock->shouldReceive('bootMyTrait')->once();

    から使用されることを意味し、それは部分的に作ります

  4. $mock->__construct();

    このようにして、デフォルトのクラスコンストラクタを実行できます。モックを作成するときには、コンストラクタが使用されていないように見えるので、他の方法でテストすることはできません。元のクラスコンストラクターが起動されていることを確認したい場合は、手動でオブジェクトコンストラクターメソッドを起動する必要があります。

+0

ありがとうございます!なぜこれがLaravelのMockeryラッパーではうまくいかないのか分かりませんが、私はそれを取るでしょう! – timbroder