You can probably do something like this
$modelMock = Mockery::mock('App\Model');
// Other stuff here
$this->app->instance('App\Model', $modelMock);
Summer Sale! All accounts are 50% off this week.
Hi,
I have this code and I want to test that the model's attributes are assigned properly:
class SubTask extends Model
{
public function add($data)
{
$this->fill($data);
$task = Task::find($data['parent_task_id']);
$this->project_id = $task->project->id;
$this->save();
}
}
Is it possible to mock Task::find so it can provide mocked $task object where I can set $task->project->id?
Here is the test that I'm thinking of:
public function add_subtask()
{
$data = [
'name' => 'Subtask One',
'parent_task_id' => 1
];
// need to mock Task::find here
$subTask = m::mock('SubTask')->makePartial();
$subTask->shouldReceive('save')->once();
$subTask->add($data);
$this->assertEquals($subTask->name, $data['name']);
$this->assertEquals($subTask->project_id, $task->project->id);
}
What bobby suggested would work for normal facades but models don't work that way. It is actually very difficult to unit test models and it is best to try and treat them like value objects as much as possible.
I think in terms of just getting this to work for you would be to use Laravel's IoC container to get the Task model so you would have $task = app(Task::class)->find($data['parent_task_id']);. This way what bobby has suggest would work.
I would suggest perhaps creating a command that way you can have dependency injection working.
class CreateSubTaskJob extends Job implements SelfHandling
{
public $data;
public function __construct($name, $other, $attributes, $parent_task_id)
{
$data = compact('name', 'other', 'attributes', 'parent_task_id');
}
pubilc function handle(Task $taskRepo, SubTask $subTaskRepo)
{
$this->data['project_id'] = $taskRepo->find($this->data['parent_task_id'])->project->id;
return $subTaskRepo->create($this->data);
}
}
Then in your controller or where ever you can dispatch the command and it will handle everything for you:
class SubTaskController extends Controller
{
// ...
public function store(Request $request)
{
$subTask = $this->dispatchFrom(CreateSubTaskJob::class, $request);
// Do stuff
return redirect()->back()->with('message', 'Created successfully!');
}
// ...
}
Or in your testing:
/** @test **/
function it_creates_subtask()
{
$mockTask = Mockery::mock(Task::class);
$mockTask->shouldReceive('find')->with(15)->andReturn((object) ['project' => (object) ['id' => 3]);
$mockSubTask = Mockery::mock(SubTask::class);
$mockSubTask->shouldReceive('create');
(new CreateSubTaskJob('Name', 'Other', 'Attributes', 15))->handle($mockTask, $mockSubTask);
}
Please or to participate in this conversation.