Ad

Laravel Mock Should Be Called At Least Once But Called 0 Times

- 1 answer

I have an artisan command that fires a job called PasswordResetJob which iterates as it calls a method forcePasswordReset in a repository class OrgRepository, the method updates a user's table. The whole process works fine.

Now I'm trying to write a Laravel test to mock the OrgRepository class and assert that the forcePasswordReset method is called at least once, which should be the case, based on the conditions I provided to the test. In the test, I call the artisan command to fire job; (I'm using sync queue for testing) this works fine as the job gets called and the user's table gets updated as I can view my database updates directly. However, the test fails with the error: Mockery\Exception\InvalidCountException : Method forcePasswordReset() from Mockery_2_Repositories_OrgRepository should be called at least 1 times but called 0 times.

The artisan call within the test is:

Artisan::call('shisiah:implement-org-password-reset');

I have tried to make the artisan call before, as well as after this mock initialization, but I still get the same errors. Here is the mock initialization within the test

$this->spy(OrgRepository::class, function ($mock) {
        $mock->shouldHaveReceived('forcePasswordReset');
    });

What am I missing? I have gone through the documentation and searched through Google for hours. Please let me know if you need any additional information to help. I'm using Laravel version 6.0

edit

I pass the OrgRepository class into the handle method of the job class, like this:

 public function handle(OrgRepository $repository)
{
    //get orgs
    $orgs = Org::where('status', true)->get();

    foreach ($orgs as $org){
       $repository->forcePasswordReset($org);
    }
}
Ad

Answer

The problem is that you are initializing your spy after your job has already run, which means during the job it will use the real class instead of the spy.

You have to do something like this in your test:

$spy = $this->spy(OrgRepository::class);

// run your job

$spy->shouldHaveReceived('forcePasswordReset');

We tell laravel to use the spy instead of the repository, run the job and then assert that the method was called.

Jeffrey Way explains it pretty well in this screencast.

Ad
source: stackoverflow.com
Ad