2015-09-16 58 views
1

我現在被困在Laravel 4.2中(與phpunit和嘲笑),但同樣應該適用於更高版本。在Laravel中,模擬一個模型的雄辯查詢

我有一個知識庫用於我的FxRate模型。它有一個方法來獲得的外匯匯率VS GBP包含此雄辯電話:

$query = \FxRate::where('currency', $currency) 
    ->where('fx_date', $fxDate->format('Y-m-d')) 
    ->first(); 

return $query->rate_to_gbp; 

在我的單元測試,我想嘲笑這個電話,所以我可以定義將通過此調用返回的查詢結果而不是依靠數據庫來實現其中的價值。

我的嘗試是這樣的:

$mocked_query_result = (object) ['rate_to_gbp' => 1.5]; 

FxRate::shouldReceive('where') 
     ->once() 
     ->andReturn($mocked_query_result); 

但我相當肯定這不會是最初的靜態調用FxRate應該返回接受進一步where()調用和first()一些查詢對象工作。

有沒有嘲笑他的乾淨的方式?

回答

1

你應該通過你的模型的實例進倉庫的構造:

public function __construct(FXRate $model) 
{ 
    $this->model = $model; 
} 

然後將查詢變爲:

$query = $this->model->where('currency', $currency)...etc 

然後你傳遞一個嘲笑模型回購當實例它:

$mockModel = Mockery::mock('FXRate'); 
// This could be better, and you should use correct with() calls but hey, it's only an example 
$mockModel->shouldReceive('where') 
    ->twice() 
    ->andReturn($mockModel); 
$mockModel->shouldReceive('first') 
    ->once() 
    ->andReturn($mocked_query_result); 
$repo = new Repo($mockModel) 
$this->assertEquals($mocked_query_result, $repo->testableMethod()); 

進一步編輯下面的評論。你可以返回任何模型的模擬,但我覺得嘲弄真實模型與可讀性幫助:

$mockFXRate = Mockery::mock('FXRate'); 
$mockFXRate->shouldReceive('where') 
    ->once() 
    ->andReturn($mockFXRate); 
$mockFXRate->shouldReceive('first') 
    ->once() 
    ->andReturn($mocked_query_result); 
FXRate::shouldReceive('where') 
    ->andReturn($mockFXRate); 
+0

[該文檔(http://laravel.com/docs/4.2/testing#mocking-facades)說這是可能嘲笑門面;這不是問題 - 我很高興在這種情況下使用外觀。難度是鏈式方法,看起來好像我需要爲鏈中的每個方法返回一個新的模擬對象。 – harryg

+0

@harryg - 找到了你。我在編輯中採取了這種方法。也許不是最好的,所以有人可能會提出其他建議。有一個Mockery :: self()對象返回,但我有問題讓它工作,從來沒有堅持下去,所以值得一看。 – markdwhite

+0

嗯,我真不知道該作品爲'FxRate ::其中(...)'不返回FxRate'的'一個實例;它返回一個'Illuminate \ Database \ Eloquent \ Builder'實例,它接受進一步鏈接的方法。 'first()'然後返回結果。 – harryg