Tes HTTP & API
Tes HTTP adalah kontrak yang bisa dijalankan. Ia membuktikan bahwa endpoint-mu memberi status, bentuk, dan izin yang benar — dan memberitahumu saat salah satunya berubah tanpa sengaja.
Intisari
getJson,postJson, dan kawan-kawan memasang headerAcceptyang benar.assertJsonStructurememeriksa bentuk;assertJsonPathmemeriksa nilai.actingAs($user, 'sanctum')untuk menguji rute API tanpa membuat token sungguhan.Storage::fake()danUploadedFile::fake()untuk unggahan.withoutExceptionHandling()menampilkan exception asli alih-alih halaman 500 yang tidak informatif.
Menguji endpoint JSON
it('mengembalikan daftar artikel terbit', function () {
Artikel::factory()->terbit()->count(3)->create();
Artikel::factory()->draf()->count(2)->create();
$this->getJson('/api/v1/artikel')
->assertOk()
->assertJsonCount(3, 'data')
->assertJsonStructure([
'data' => [['id', 'judul', 'slug', 'terbit_pada']],
'links', 'meta',
]);
});
it('memvalidasi artikel baru', function () {
$this->actingAs(editor(), 'sanctum')
->postJson('/api/v1/artikel', ['judul' => ''])
->assertUnprocessable()
->assertJsonValidationErrors(['judul', 'isi']);
});
it('membuat artikel', function () {
$this->actingAs(editor(), 'sanctum')
->postJson('/api/v1/artikel', [
'judul' => 'Kabar Pagi',
'isi' => 'Isi lengkap.',
])
->assertCreated()
->assertJsonPath('data.judul', 'Kabar Pagi');
$this->assertDatabaseHas('artikel', ['judul' => 'Kabar Pagi']);
});
assertJsonStructure adalah pelindung kontrak API-mu. Ia gagal saat sebuah field hilang
atau berubah nama — persis kejadian yang akan memutus aplikasi klien. Pasangkan dengan
assertJsonMissing untuk field yang tidak boleh bocor, seperti
catatan_internal.
Assertion JSON yang perlu dibedakan
| Assertion | Memeriksa |
|---|---|
assertJson([...]) | Berisi sebagian struktur ini |
assertExactJson([...]) | Persis sama, tidak lebih dan tidak kurang |
assertJsonPath('data.0.judul', 'X') | Satu nilai di jalur tertentu |
assertJsonStructure([...]) | Kunci-kuncinya ada; nilainya tidak diperiksa |
assertJsonCount(3, 'data') | Jumlah elemen |
assertJsonMissing(['rahasia']) | Tidak mengandung ini |
assertJsonValidationErrors([...]) | 422 dengan field yang disebutkan |
Autentikasi di dalam tes
$this->actingAs($user); // guard default (web)
$this->actingAs($user, 'sanctum'); // rute API
$this->actingAs($admin, 'admin');
// Token dengan ability terbatas — untuk menguji pembatasannya
Sanctum::actingAs($user, ['artikel:baca']);
$this->postJson('/api/v1/artikel', [...])->assertForbidden();
Unggahan berkas
it('menyimpan gambar sampul', function () {
Storage::fake('s3');
$berkas = UploadedFile::fake()->image('sampul.jpg', 1200, 630);
$this->actingAs(editor())
->post(route('artikel.store'), ['judul' => 'X', 'sampul' => $berkas])
->assertRedirect();
Storage::disk('s3')->assertExists('sampul/'.$berkas->hashName());
});
it('menolak berkas yang terlalu besar', function () {
$besar = UploadedFile::fake()->create('dokumen.pdf', 20_000); // 20 MB
$this->actingAs(editor())
->post(route('artikel.store'), ['sampul' => $besar])
->assertSessionHasErrors('sampul');
});
Melihat error yang sebenarnya
it('sesuatu yang sedang rusak', function () {
$this->withoutExceptionHandling(); // lempar exception asli, bukan halaman 500
$this->get('/artikel/1')->assertOk();
});
$response->dump(); // cetak isi respons
$response->dumpHeaders();
$response->dumpSession();
Tanpa withoutExceptionHandling(), tes yang gagal cuma bilang "mengharapkan 200, mendapat
500". Dengannya, kamu melihat exception dan baris persisnya. Nyalakan saat sedang men-debug, matikan lagi
setelah selesai — kamu tetap ingin menguji bahwa error ditangani dengan benar di tes yang lain.
Menguji halaman Inertia dan Livewire
// Inertia
$this->get('/artikel')->assertInertia(fn (Assert $page) => $page
->component('Artikel/Index')
->has('artikel.data', 3)
->where('filter.q', null));
// Livewire
Livewire::test(CariArtikel::class)
->set('kata', 'kabar')
->assertSee('Kabar Pagi')
->assertDontSee('Berita Sore');
Yang wajib punya tes
- Setiap aturan otorisasi — dari sisi yang boleh dan yang tidak boleh.
- Setiap aturan validasi yang melindungi integritas data.
- Bentuk respons setiap endpoint API publik.
- Setiap alur yang menyentuh uang atau data pribadi.
- Setiap bug yang pernah terjadi — tulis tesnya sebelum memperbaikinya.
Latihan: tulis tes yang memastikan endpoint daftar artikel tidak mengembalikan field
catatan_internal untuk pengguna biasa, tapi mengembalikannya untuk editor. Ini satu tes yang
mencegah satu kelas kebocoran data.
Rangkuman ini sengaja dipangkas ke bagian yang dipakai di roadmap. Buka sumber aslinya saat kamu butuh detail lengkap atau referensi parameter.