Reputation: 24107
I'm stuck on Laravel 4.2 for now (with phpunit and mockery) but the same should apply to later versions.
I have a Repository for my FxRate
model. It has a method to get an FX rate vs GBP which contains this eloquent call:
$query = \FxRate::where('currency', $currency )
->where('fx_date', $fxDate->format('Y-m-d') )
->first();
return $query->rate_to_gbp;
In my unit test I'd like to mock this call so I can define the query result that would be returned by this call rather than relying on the database to have a value within it.
My attempt goes something like this:
$mocked_query_result = (object) ['rate_to_gbp' => 1.5];
FxRate::shouldReceive('where')
->once()
->andReturn($mocked_query_result);
But I'm fairly sure this won't work as the initial static call to FxRate
should return some query object that accepts a further where()
call and a first()
.
Is there a clean way of mocking this?
Upvotes: 5
Views: 10031
Reputation: 2449
You should pass an instance of your model into the repository in the constructor:
public function __construct(FXRate $model)
{
$this->model = $model;
}
Then your query becomes:
$query = $this->model->where('currency', $currency)...etc
Then you pass a mocked model to the repo when you instantiate it:
$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());
Further edit following comments. You can return a mock of any model but I find mocking the real model helps with readability:
$mockFXRate = Mockery::mock('FXRate');
$mockFXRate->shouldReceive('where')
->once()
->andReturn($mockFXRate);
$mockFXRate->shouldReceive('first')
->once()
->andReturn($mocked_query_result);
FXRate::shouldReceive('where')
->andReturn($mockFXRate);
Upvotes: 3