2015-09-16 3 views
1

Я застрял на Laravel 4.2 сейчас (с phpunit и насмешкой), но то же самое относится к более поздним версиям.В Laravel, высмеивая красноречивый запрос по модели

У меня есть репозиторий для моей модели FxRate. Он имеет метод, чтобы получить скорость FX против 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 :: where (...)' не возвращает экземпляр 'FxRate'; он возвращает экземпляр 'Illuminate \ Database \ Eloquent \ Builder', который принимает дальнейшие цепные mothods. 'first()' затем возвращает результат. – harryg

Смежные вопросы