Test yang baik pendek, eksplisit, dan memakai assertion bawaan framework — bukan assertTrue untuk segalanya. Laravel menyediakan ratusan assertion berbasis nama-natural persis untuk itu: dibaca seperti kalimat (assertRedirect, assertDatabaseHas), sehingga test tetap dimengerti enam bulan kemudian tanpa membuka implementasinya. Chapter ini merangkum yang paling sering dibutuhkan per kelompok: assertion HTTP, assertion database, fake untuk layanan eksternal, dan helper waktu. Dasar teorinya sudah dibahas di Konsep Testing ; kartu ini dirancang untuk dibuka persis saat sedang menulis test.

Satu kenyamanan yang membuat assertion HTTP terasa lancar: semuanya berantai pada objek response. Kode $response->assertStatus(200)->assertSee('Berhasil') mengeksekusi dua pemeriksaan pada satu objek yang sama, dan kegagalan pertama langsung menghentikan test dengan pesan yang menyebut persis assertion mana yang gugur. Perilaku berantai inilah yang membuat test Laravel terasa seperti menulis daftar harapan, bukan prosedur ritual.

Assertion HTTP #

AssertionMemeriksaKapan dipakai
assertStatus(200)Kode status persiskasus umum
assertOk() / assertCreated() / assertNoContent()200 / 201 / 204 ringkasendpoint API
assertNotFound() / assertForbidden() / assertUnauthorized()404 / 403 / 401halaman terproteksi
assertRedirect('/login')Status 3xx + Locationform berhasil → redirect
assertSee('Berhasil')String ada di body HTMLcek konten halaman
assertSeeInOrder([...])Kemunculan berurutanurutan daftar
assertDontSee('error')String tidak ada—
assertViewHas('tugas')Data yang dikirim ke viewcontroller + view
assertSessionHas('status')Flash session terpasangpola PRG
assertSessionHasErrors('judul')Error validasi tersimpanform invalid
assertCookie('ingat') / assertHeader(...)Cookie / header responsekeamanan

Dengan berpindah ke endpoint JSON, keluarga assertJson* mengambil alih: assertJson(['data' => [...]]) untuk struktur, assertJsonPath('data.0.judul', 'Belajar Laravel') untuk satu nilai, assertJsonCount(3, 'data') untuk jumlah item, dan assertJsonStructure(['data' => ['*' => ['id', 'judul']]]) untuk bentuk tanpa nilai — semuanya dibahas di HTTP Tests dan API Testing .

Assertion Database #

AssertionMemeriksa
assertDatabaseHas('tugas', ['judul' => 'Belajar Laravel'])Baris cocok ada
assertDatabaseMissing('tugas', [...])Baris cocok tidak ada
assertDatabaseCount('tugas', 3)Jumlah baris persis
assertModelExists($tugas)Model benar-benar tersimpan
assertModelMissing($tugas)Model sudah terhapus
assertSoftDeleted($tugas)Model soft-deleted

Assertion ini bekerja langsung ke database apa pun drivernya, menjadikannya jembatan antara test HTTP dan data — pola lengkapnya di Database Testing . Aturan praktis pemilihannya: gunakan assertDatabaseHas saat test tidak peduli modelnya (misal memverifikasi baris pivot atau data lewat query builder), dan gunakan assertModelExists saat objek model sedang kita pegang — keduanya membaca tabel yang sama, beda hanya kenyamanan argumennya.

Inventaris Fake #

Fake mengganti layanan eksternal dengan peniru in-memory supaya test cepat dan deterministik.

FakePasangAssertion utama
Mail::fake()Mail::assertSent(Mailable::class)assertQueued, assertNotSent, assertSentTimes, assertNothingSent
Notification::fake()Notification::assertSentTo($user, Nama::class)assertNotSentTo, assertSentToTimes, assertNothingSentTo
Queue::fake()Queue::assertPushed(Job::class)assertPushedOn('nama-queue', ...), assertNotPushed
Event::fake()Event::assertDispatched(Event::class)assertNotDispatched, assertDispatchedTimes
Bus::fake()Bus::assertDispatched(Command::class)assertBatched, assertNotDispatched
Storage::fake('foto')Storage::disk('foto')->assertExists($path)assertMissing, assertCount, assertDirectoryEmpty
Http::fake()Http::assertSent(fn ($r) => $r->url() === ...)assertNotSent, assertNothingSent

Untuk Storage::fake(), assertion berjalan pada disk tiruan itu sehingga file tidak pernah menyentuh disk sungguhan. Kombinasi fake dan job dibedah di Queue dan Event Testing , sedangkan tipologi lengkapnya di Mocking dan Fakes .

Helper Waktu dan Trait #

Dua helper membuat test waktu jadi deterministik. travelTo() (atau travel(5)->minutes()) membekukan jam aplikasi sehingga logika terjadwal bisa diuji tanpa menunggu, sedangkan actingAs($user) membuat request test seolah-olah datang dari user yang sedang login — pola standar di Authentication Testing .

Untuk isolasi database, tiga trait berbagi tugas yang sama dengan strategi berbeda. Pilihan default kami adalah RefreshDatabase: migrasi hanya dijalankan sekali per proses test, lalu tiap test dibungkus transaksi yang dibatalkan di akhir — cepat dan aman sekaligus. Dua trait lainnya ada untuk kasus tepi: DatabaseMigrations paling bersih namun paling lambat karena migrasi ulang tiap test, sedangkan DatabaseTruncations unggul saat test melewati proses Schema berat atau berjalan paralel.

TraitStrategi reset
RefreshDatabaseMigrasi sekali lalu transaksi per test — default terbaik
DatabaseMigrationsMigrasi ulang penuh tiap test — lambat, paling bersih
DatabaseTruncationsTruncate tabel tiap test — cepat untuk ratusan test

Sebagai bukti bahwa kartu ini bekerja, berikut test mini yang memakai actingAs, RefreshDatabase, assertStatus, dan assertDatabaseHas — persis seperti yang kami jalankan di sandbox Course ini:

php
public function test_halaman_tugas_menampilkan_daftar(): void
{
    $user = User::factory()->create(['name' => 'Budi']);

    $response = $this->actingAs($user)->get('/tugas');

    $response->assertStatus(200);
    $this->assertDatabaseHas('users', ['email' => $user->email]);
}

Output yang Dihasilkan (php artisan test tests/Feature/ReferensiTest.php):

text
  PASS  Tests\Feature\ReferensiTest
  ✓ halaman tugas menampilkan daftar                    0.16s

  Tests:    1 passed (2 assertions)
  Duration:  0.24s

Kode yang teruji masih bisa bocor secara keamanan bila kita lengah dalam mengatur lapisan proteksinya. Kartu berikutnya merangkum seluruh checklist keamanan Course ini: Referensi Keamanan .