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:

php
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:

text
dieksekusi_oleh_fake: false

Counter 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:

php
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:

AssertionMemeriksa
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.

php
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:

php
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):

text
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 .