簡體   English   中英

Mockery和Laravel構造函數注入

[英]Mockery and Laravel constructor injection

我正在使用帶有php單元的laravel 5來創建一個laravel包。 我有一個Repository ..

namespace Myname\Myapp\Repositories;

use Myname\Myapp\Models\PersonModel;

class PersonRepository
{
    protected $personModel;

    public function __construct(PersonModel $personModel)
    {
        $this->personModel = $personModel;
    }

    public function testFunction($var)
    {
        return $this->personModel->find($var);
    }
}

..which實現了一個Model

namespace Myname\Myapp\Models;

use Illuminate\Database\Eloquent\Model;

class PersonModel extends Model
{
    protected $table = 'person';
}

Laravels IoC自動將PersonModel注入PersonRepository的構造函數中。

我正在編寫單元測試,我想使用mock來模擬PersonModel模型,因此我在測試期間沒有訪問數據庫。

namespace Myname\Myapptests\unit;

use Mockery;

class PersonRepositoryTest extends \Myname\Myapptests\TestCase
{
     /**
     * @test
     */ 
     public function it_returns_the_test_find()
     {
         $mock = Mockery::mock('Myname\Myapp\Models\PersonModel')
            ->shouldReceive('find')
            ->with('var');

         $this->app->instance('Myname\Myapp\Models\PersonModel', $mock);
         $repo = $this->app->make('Myname\Myapp\Repositories\PersonRepository');
         $result = $repo->testFunction('var');

         $this->assert...
     }
}

當我運行測試時,我收到一個錯誤

1)Myname \\ Myapptests \\ unit \\ PersonRepositoryTest :: it_returns_the_test_find ErrorException:傳遞給Myname \\ Myapp \\ Repositories \\ PersonRepository :: __ construct()的參數1必須是Myname \\ Myapp \\ Models \\ PersonModel的實例,給出Mockery \\ CompositeExpectation的實例

從我所讀到的,mockery擴展了它正在模擬的類,因此應該沒有注入擴展類代替類型提示父類(PersonModel)的問題

顯然我錯過了一些東西。 其他示例明確地將模擬對象注入到他們正在測試的類中。 Laravels IoC(應該)為我做這件事。 我必須綁定任何東西嗎?

我有一種感覺,雖然嘲弄對象沒有按我想象的方式創建(擴展PersonModel),否則我認為我不會看到這個錯誤。

問題是當你創建你的模擬時:

$mock = Mockery::mock('Myname\Myapp\Models\PersonModel')
    ->shouldReceive('find')
    ->with('var');

所以這:

$mock = Mockery::mock('Myname\Myapp\Models\PersonModel')
var_dump($mock);
die();

將輸出如下內容: Mockery_0_Myname_Myapp_Models_PersonModel

但是這個:

$mock = Mockery::mock('Myname\Myapp\Models\PersonModel')
    ->shouldReceive('find')
    ->with('var');
var_dump($mock);
die();

將輸出: Mockery\\CompositeExpectation

所以嘗試做這樣的事情:

$mock = Mockery::mock('Myname\Myapp\Models\PersonModel');
$mock->shouldReceive('find')->with('var');

$this->app->instance('Myname\Myapp\Models\PersonModel', $mock);
$repo = $this->app->make('Myname\Myapp\Repositories\PersonRepository');
$result = $repo->testFunction('var');

雖然Fabio給出了一個很好的答案 ,但這里的問題實際上是測試設置。 Mockery的模擬對象確實符合契約 ,並將在方法參數中傳遞instanceof測試和類型提示。

原始代碼的問題在於被調用的方法鏈最終返回期望而不是模擬。 我們應該首先創建一個模擬,然后為該模擬添加期望。

要修復它,請更改:

$mock = Mockery::mock('Myname\Myapp\Models\PersonModel')
    ->shouldReceive('find')
    ->with('var');

進入:

$mock = Mockery::mock('Myname\Myapp\Models\PersonModel');
$mock->shouldReceive('find')->with('var');

變量$mock現在將實現PersonModel

獎金:

而不是'Myname\\Myapp\\Models\\PersonModel' ,使用PersonModel::class 這是一個更友好的IDE,並將在以后重構代碼時幫助您。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM