I want to test a service who change the state of a model.
this is my model :
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Color extends Model
{
protected $table = 'color';
protected $connection = 'someconnection';
public $timestamps = false;
}
and this is the service :
<?php
namespace App\Services;
use App\Models\Color;
class ColorChanger
{
public function changeColor(Color $color): void
{
switch($color->name) {
case 'green':
$color->name = 'red';
break;
case 'red':
$color->name = 'orange';
break;
}
$color->save();
}
}
I tried to make a simple test like this :
<?php
namespace Tests\Unit\Services;
use App\Models\Color;
use App\Services\ColorChanger;
use Tests\TestCase;
class ColorChangerTest extends TestCase
{
public function test_color_has_changed_from_green_to_red()
{
$color = new Color();
$color->name = 'green';
$colorChanger = new ColorChanger();
$colorChanger->changeColor($color);
$this->assertEquals('red', $color->name);
}
}
but when I run the test it gives me an error because the save
method is trying to update the database.
I am in a test environment and there is no database available.
I tried factories, I tried to mock the Color Model to prevent the save
method to connect to the database, but in vain.
I ended up to use the repository pattern, I inject it into the service ColorChanger and mock its save method during the test.
class ColorRepo
{
public function save(Color $color): bool
{
return $color->save();
}
class ColorChanger
{
private ColorRepo $colorRepo;
public function __construct(ColorRepo $colorRepo): void
{
$this->colorRepo = $colorRepo;
}
public function changeColor(Color $color): void
{
switch($color->name) {
case 'green':
$color->name = 'red';
break;
case 'red':
$color->name = 'orange';
break;
}
$this->colorRepo->save($color);
}
}
Isn't there another simple way to turn off the models save method ? Because using the repository pattern adds extra codes which looks to me really too much for this simple case.
I'm thinking about the creation of a
class
calledMockable
or something of the like that would look like this:and call it like
of course, you will need to change
$isDebug
totrue
if you are debugging.