Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

dominicsears's avatar

[HELP] Testing mail assertions inside of a job

Hello everyone! I've been stumped over this issue on some assertions of a mailable inside of a job.

I could be doing it wrong as far as sending a mail inside of a job, but I've got these assertions working before, just now it's not working and I think it stopped working after I put DB transactions inside the controller that handles registration.

The test passes when it shouldn't pass because I have a dd in there.

routes/api.php

Route::post('/register', [AuthController::class, 'register'])
    ->middleware('throttle:10,1')
    ->name('api.register');

app/Http/Controllers/API/AuthController.php

app/Jobs/SendAdminNewUserRequest

class SendAdminNewUserRequest implements ShouldQueue
{
    use Queueable, Dispatchable, InteractsWithQueue;

    public function __construct(
        protected readonly int $newUserRequestId,
    ) {
    }

    public function handle(): void
    {
        $newUserRequest = NewUserRequest::query()
            ->where('id', $this->newUserRequestId)
            ->firstOrFail();

        $groupAdmins = $newUserRequest->group->admins->pluck('email')->all();

        // NewUserRequestAdminNotify is not a notification, just a bad name
        Mail::to($groupAdmins)
            ->queue(new NewUserRequestAdminNotify($newUserRequest));
    }
}

app/Mail/NewUserRequestAdminNotify.php

The problem is when I test some assertions, it doesn't assert anything in the Mail::queued callback. Maybe I'm misunderstanding, but it worked before testing the assertions.

This is in PHPUnit

tests/Feature/Http/API/AuthTest.php

One issue might've been my setup with the testing enviornment. I'm using Redis for handling queues for non-test code, but I think I might've had a misconfiguration that made it run on Redis still instead of sync? It's interesting.

.env.test

APP_NAME="Application"
APP_ENV=local
APP_KEY=base64:1234
APP_DEBUG=true
APP_URL=https://application.test

LOG_CHANNEL=stack

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=application-phpunit
DB_USERNAME=root
DB_PASSWORD=

CACHE_DRIVER=redis
CACHE_STORE=redis
SESSION_DRIVER=redis
SESSION_LIFETIME=1080
QUEUE_CONNECTION=sync

REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379
0 likes
2 replies
LaryAI's avatar
Level 58

The issue you're facing with the Mail::queued assertion not being reached could be due to a few reasons. Let's go through some potential solutions and debugging steps:

  1. Ensure Queue is Set to Sync: Since you're using Redis in your non-test environment, make sure that your test environment is correctly set to use the sync driver. You've already set QUEUE_CONNECTION=sync in your .env.test, which is correct. Double-check that your test environment is loading this configuration.

  2. Check Job Dispatching: Ensure that the job SendAdminNewUserRequest is being dispatched correctly. You can add a dd or Log::info statement in the handle method of the job to confirm it's being executed.

  3. Verify Mail Fake Setup: Ensure that Mail::fake() is called before the action that triggers the mail. In your test, it seems to be set up correctly, but double-check the order of operations.

  4. Check for Transaction Issues: Since you're using database transactions, ensure that the transaction is committed before the job is dispatched. In your AuthController, the transaction is committed after dispatching the job, which is correct. However, if there's any exception or issue before the commit, the job might not have the expected data.

  5. Debug the Test: Add a dd or Log::info in the handle method of the SendAdminNewUserRequest job to ensure it's being called and that the Mail::to(...)->queue(...) line is executed.

  6. Test the Mail Directly: Instead of relying on the job, you can test the mail directly by calling the handle method of the job in your test to see if the mail is queued as expected.

Here's a modified version of your test to help debug:

This approach directly tests the mail sending logic by calling the job's handle method, which can help isolate whether the issue is with the job dispatching or the mail queuing. Adjust the test as needed based on your application's specifics.

dominicsears's avatar
dominicsears
OP
Best Answer
Level 7

@LaryAI I believe my configuration got in the way somehow. Regardless, I resorted to manually triggering the jobs and faking everything.

Queue::assertPushed(SendAdminNewUserRequest::class, function ($job) {
    $job->handle();
    return true; // return true for the assertion
});

Please or to participate in this conversation.