Issuing the invoice is the feature this series tests. Marking the order paid is the payment step after that, and the job is the one from the job class lesson. The happy path dispatches a job. The test should prove the job was pushed, and it should not run the job. Queue::fake() records dispatches and runs nothing, so a payment job cannot charge anything during the test.
Test-driven Laravel · Lesson 3
Faking the queue
Video
01 Assert the class and the order it carries
Fake first. Then make the request. Then assert the job class and the id it was given.
it('dispatches a job to mark the order paid', function () {
Queue::fake();
$user = User::factory()->create();
$this->actingAs($user)
->post('/orders', [
'number' => '1042',
])
->assertRedirect();
Queue::assertPushed(MarkOrderPaid::class, function (MarkOrderPaid $job) {
return $job->orderId === Order::query()->firstOrFail()->id;
});
});The order row is still there to assert. The job’s handle() did not run, so the status is still pending. If the test needs the status to become paid, call the job’s handle() yourself, or use Queue::fake() only in the test that cares about dispatch.
Bus::fake() is the matching tool when the code dispatches a batch rather than a single job. assertPushed will not see a batch.
02 Run handle() when the test is about the status
Queue::fake() is the wrong tool for “the order becomes paid”. That sentence is about handle(), not about dispatch. Call the job with the id the request stored. The status assertion then belongs to the job, and the dispatch assertion stays in the test above.
it('marks the order paid when the job runs', function () {
$order = Order::factory()->create(['status' => 'pending']);
(new MarkOrderPaid($order->id, 'attempt-1'))->handle();
expect($order->fresh()->status)->toBe('paid');
});Do not combine them. A test that fakes the queue and then calls handle() is two acts. The fake test proves the controller dispatched. This one proves the job writes paid. A retry of handle() is Make the job safe to run twice, and it expects the second call to leave the row alone.
assertPushedOn('payments', MarkOrderPaid::class) belongs in the test only when the queue name is part of the behaviour. The job class lesson sets that name in the constructor. Asserting it here catches a dispatch that forgot the class and landed on default, where a report worker would delay the payment.
Recap
You can prove a job was pushed without running it, and call handle() only in the test that is about the status.
Queue::fake()runs nothing, so a payment job cannot charge during the dispatch test.assertPushedcan read the id on the job.- A batch is
Bus::fake(), notassertPushed.
Check yourself · 3 questions
Question 1 of 3The test fakes the queue and asserts the order is paid. Why is that the wrong pair?