Reputation: 862
I'm using Laravel 5.2, phpunit 5.0.0 and PHP 7.0.3 and try to write a test with database interaction that touches an Eloquent models scope method.
I have a something like that:
class Picture extends Illuminate\Database\Eloquent\Model {
...
public function scopeGetPictureNameById($oQuery, $pictureHId) {
return $oQuery->select('name')->where('h_id', '=', $pictureHId)->first()->name;
}
}
class someHelperClass {
public function someMethod($pictureId) {
$pictureName = Picture::getPictureNameById($pictureId);
return "name is " . $pictureName;
}
}
class SomeTest extends TestCase {
use DatabaseMigrations;
protected $someHelper;
public function setUp() {
parent::setUp();
$this->someHelper = new SomeHelper();
}
/**
* @test
*/
public function someMethodTest() {
$expectedName = "test";
$this->assertEquals("name is " . $expectedName, $this->someHelper->someMethod());
}
}
I seed the Database with a Picture record where the name is set to "test".
The first thing I thought was that I would not have to mock the scope call, because all I need is in the Database. And since the (non simplified) code I have works outside the test, I guess that scope calls don't work in phpunit. (I get a "Trying to get property of non-object" Exception).
Okay, so I tried to mock the call with Mockery:
class SomeTest extends TestCase {
use DatabaseMigrations;
protected $someHelper;
public function setUp() {
parent::setUp();
$this->someHelper = new SomeHelper();
}
/**
* @test
*/
public function someMethodTest() {
$expectedName = "test";
$mockedPicture = Mockery::mock('overload:App\Models\Picture');
$mockedPicture->shouldReceive('getPictureNameById')->andReturn('test');
//also tried this: $mockedPicture->shouldReceive('scopeGetPictureNameById')->andReturn('test');
$this->assertEquals("name is " . $expectedName, $this->someHelper->someMethod());
}
}
All I get is the "Could not load mock App\Models\Picture, class already exists". So how can I properly mock query scope calls like Picture::getPictureNameById($pictureId)?
Upvotes: 3
Views: 1314
Reputation: 1658
I would use dependency injection instead of calling methods on the Picture class statically. So something like this:
class someHelperClass {
protected $picture;
public function __construct(Picture $picture) {
$this->picture = $picture;
}
public function someMethod($pictureId) {
$pictureName = $this->picture->getPictureNameById($pictureId);
return "name is " . $pictureName;
}
}
Then in your test:
public function someMethodTest() {
$expectedName = "test";
$mockedPicture = Mockery::mock('App\Models\Picture');
$mockedPicture->shouldReceive('getPictureNameById')->andReturn('test');
$someHelper = new SomeHelper($mockedPicture);
$this->assertEquals("name is " . $expectedName, $someHelper->someMethod(1));
}
Upvotes: 1