Menguji kode antrean berarti menjawab dua pertanyaan yang berbeda. Pertama: apakah job yang tepat terkirim ke antrean yang tepat, dengan payload yang tepat? Kedua: apakah job itu benar-benar bekerja ketika worker menjalankannya? Laravel menyediakan dua jalur untuk masing-masing — Queue::fake() menggantikan antrean agar dispatch bisa diinspeksi tanpa worker, sementara test integrasi menjalankan queue:work sungguhan di dalam test. Pada chapter penutup section ini kita bangun test suite yang menutup keduanya, dari assertion dasar sampai pengujian chain, batch, dan worker nyata.
Queue::fake dan Assertion Dasar #
Queue::fake() menggantikan queue manager dengan QueueFake yang mencatat setiap push. Job tidak dieksekusi — justru itulah yang kita ukur:
public function test_fake_mencatat_push_tanpa_mengeksekusi_job(): void
{
Queue::fake();
dispatch(new SendAnalyticsJob(9));
Queue::assertPushed(SendAnalyticsJob::class);
Queue::assertPushedTimes(SendAnalyticsJob::class, 1);
Queue::assertNotPushed(GenerateInvoiceJob::class);
fwrite(STDERR, 'dieksekusi_oleh_fake: '
.var_export((int) Cache::get('analytics_terkirim:9') === 1, true)."\n");
}Output yang Dihasilkan:
dieksekusi_oleh_fake: falseCounter analytics_terkirim:9 tetap nol — bukti handle() tidak pernah berjalan — padahal assertPushed lulus. Fake memutus koneksi antara dispatch dan eksekusi, sehingga test tetap cepat dan tanpa efek samping.
Inspeksi Payload dan Nama Antrean #
Assertion menerima closure untuk memeriksa isi job yang ter-push, dan assertPushedOn mengunci nama antreannya:
public function test_inspeksi_payload_dan_nama_antrean(): void
{
Queue::fake();
dispatch(new SendAnalyticsJob(7));
dispatch((new SendAnalyticsJob(8))->onQueue('analytics'));
Queue::assertPushed(SendAnalyticsJob::class, 2);
Queue::assertPushed(function (SendAnalyticsJob $job) {
return $job->userId === 7;
});
Queue::assertPushedOn('analytics', SendAnalyticsJob::class,
function (SendAnalyticsJob $job) {
return $job->userId === 8;
});
Queue::assertCount(2);
}Peta assertion yang paling sering kita pakai:
| Assertion | Memeriksa |
|---|---|
assertPushed(Job::class) | minimal satu job kelas itu ter-push |
assertPushed(Job::class, 2) atau assertPushedTimes(...) | jumlah push tepat |
assertPushedOn('queue', Job::class) | job masuk antrean bernama |
assertPushed(fn ($job) => ...) | payload job lolos inspeksi closure |
assertNotPushed(Job::class) | job kelas itu tidak ter-push |
assertNothingPushed() | tidak ada job sama sekali |
assertCount($n) | total semua job yang ter-push |
Bus::fake untuk Chain dan Batch #
Queue::fake beroperasi di level antrean, sedangkan chain dan batch dikirim lewat command bus. Karena itu keduanya diuji dengan Bus::fake beserta assertion khususnya — inilah pembeda mendasar dua fake tersebut. Bus::fake juga menangkap dispatch berbasis class secara umum melalui Bus::assertDispatched(SomeJob::class) dengan closure inspeksi yang sama persis seperti Queue::assertPushed, hanya berbeda kata kerja: dispatched untuk bus, pushed untuk antrean.
public function test_menguji_chain_dengan_bus_fake(): void
{
Bus::fake();
Bus::chain([
new ValidateOrderJob('INV-900'),
new ChargePaymentJob('INV-900'),
new GenerateInvoiceJob('INV-900'),
])->dispatch();
Bus::assertChained([
new ValidateOrderJob('INV-900'),
new ChargePaymentJob('INV-900'),
new GenerateInvoiceJob('INV-900'),
]);
}
public function test_menguji_batch_dengan_bus_fake(): void
{
Bus::fake();
Bus::batch([
new ImportRowJob(1),
new ImportRowJob(2),
new ImportRowJob(3),
])->name('Import pesanan')->dispatch();
Bus::assertBatched(function (PendingBatch $batch) {
return $batch->name === 'Import pesanan'
&& $batch->jobs->count() === 3;
});
Bus::assertBatchCount(1);
}assertChained membandingkan urutan lengkap anggota chain, sedangkan closure assertBatched menerima PendingBatch — nama, daftar job, dan opsi batch bisa diperiksa satu per satu sebelum batch benar-benar dikirim. Keduanya lulus tanpa menjalankan satu pun job: yang diuji adalah keputusan pengiriman, bukan eksekusinya.
Test Integrasi dengan Worker Sungguhan #
Semua fake di atas tidak menjamin handle() benar. Ketika yang ingin kita verifikasi justru isi job — query database yang dijalankan, cache yang ditulis, logika rate limit dari chapter sebelumnya — kita biarkan antrean asli bekerja: dispatch job, jalankan queue:work --stop-when-empty di dalam test, lalu assert efek sampingnya. Efek samping inilah ukuran kebenaran test integrasi, bukan keberadaan job di antrean:
public function test_worker_sungguhan_mengeksekusi_job(): void
{
dispatch(new SendAnalyticsJob(5));
dispatch((new SendAnalyticsJob(5))->onQueue('analytics'));
Artisan::call('queue:work', [
'--queue' => 'analytics,default',
'--stop-when-empty' => true,
'--max-time' => 20,
]);
fwrite(STDERR, 'terkirim_sungguhan: '
.(int) Cache::get('analytics_terkirim:5')."\n");
fwrite(STDERR, 'jobs_tersisa: '.DB::table('jobs')->count()."\n");
$this->assertSame(2, (int) Cache::get('analytics_terkirim:5'));
$this->assertSame(0, DB::table('jobs')->count());
}Output yang Dihasilkan (seluruh suite berjalan):
dieksekusi_oleh_fake: false
fake_dasar: lulus
inspeksi_payload: lulus
tidak_terpush: lulus
bus_fake_chain: lulus
bus_fake_batch: lulus
terkirim_sungguhan: 2
jobs_tersisa: 0
failed_jobs: 0
worker_integration: lulus
PASS Tests\Feature\QueueTestingTest
✓ fake mencatat push tanpa mengeksekusi job 0.14s
✓ inspeksi payload dan nama antrean 0.01s
✓ tidak ada job lain terpush 0.01s
✓ menguji chain dengan bus fake 0.01s
✓ menguji batch dengan bus fake 0.01s
✓ worker sungguhan mengeksekusi job 3.02s
Tests: 6 passed (16 assertions)Perhatikan durasinya: lima test berbasis fake selesai di bawah 0,2 detik, sementara test worker sungguhan butuh 3 detik. Proporsi ini adalah pola yang sehat — mayoritas test cepat dengan fake, sedikit test integrasi yang mahal tapi meyakinkan. Opsi --queue=analytics,default juga ikut teruji di sini: worker hanya memproses antrean yang diawasinya, jadi nama antrean yang salah bukan sekadar gagal assertion, melainkan job yang menggantung tanpa pernah dieksekusi.
Dengan ini perjalanan kita di section queue lengkap: dari konsep antrean, pembuatan job, dispatch, worker, retry, hingga batch, chain, rate limit, dan strategi pengujian. Pola yang sama — pindahkan pekerjaan berat ke belakang layar, lalu awasi dan uji — akan terus muncul di topik lanjutan seperti Laravel Horizon dan monitoring produksi. Rujukan assertion lainnya ada di dokumentasi Mocking dan dokumentasi Queues .