Home > Software design >  How can I mock a service class inside a Laravel Job?
How can I mock a service class inside a Laravel Job?

Time:01-13

I want to mock a service who call a third party, but I can't figure it out.

I have a controller method who has a service injected on it and do stuff:

public function store(Request $request, MyService $myService)
{
    $data = $request->validated();

    $myService->create($data, $request->user());

    return response()->json();
}

In this service, I call a job to do other stuffs:

MyJob::dispatch($manager);

My job is built like this:

public function __construct(private Manager $manager)
{
}

public function handle()
{
    // THE SERVICE I WANT TO MOCK
    $this->managementService = resolve(ManagementService::class, ['manager_id' => $this->manager->id]);
    $this->doStuff();
}

private function doStuff() {
    $this->managementService->startManagement();
}

In ManagementService I want to mock the function callApi:

public function startManagement()
{
    $data = $this->callApi('/thirdparty/call');

    return $data;
}

SO, in my test I try to mock the ManagementService and call my route who do all these things

$this->mock(ManagementService::class, function ($mock) {
    $mock->shouldReceive('callApi')->andReturn('none');
});

$response = $this->actingAs(User::factory()->create())->post('/myroute', [
    'manager_id' => 4,
]);

But it seems this mock is never used, it's still going into the "normal" Management Service, because when I dump $data in the startManagement method when I launch tests, it's not returning 'none'.

What am I doing wrong?

Thanks

CodePudding user response:

The code that you post is not very clear but if i understand correctly you like to mock a hard dependency thats why your mock never called because you never register it.

Just add the string overload before the class name in the mock method.

CodePudding user response:

Figured it out by injecting my service directly in the job

MyJob::dispatch($manager, resolve(ManagementService::class,  ['manager_id' => $this->manager->id]));

And inside the service instance it via constructor instead of in the handle

public function __construct(public Manager $manager, ManagementService $managementService)
{
    $this->managementService = $managementService;
}

Then in my test, my mock is instancied like this:

$mock = Mockery::mock(ManagementService::class);
        $mock->shouldReceive('callApi')
             ->once()
             ->andReturn('none');

Thanks to all

  • Related