โ† Semua pembelajaran / Laravel Nol โ†’ Enterprise
Fase 6 ยท Testing & Kualitas Kode

Tes database

Tes yang menyentuh database adalah tes yang paling meyakinkan, asalkan tiap tes tidak mewarisi kekacauan tes sebelumnya. Laravel menyediakan tiga strategi dengan biaya yang berbeda.

Sumber asli laravel.com Resmi Rangkuman ~5 menit baca

Intisari

  • RefreshDatabase membungkus tiap tes dalam transaksi lalu me-rollback โ€” cepat, dan yang paling sering dipakai.
  • DatabaseMigrations menjalankan ulang seluruh migrasi tiap tes โ€” sangat lambat, jarang perlu.
  • DatabaseTruncation mengosongkan tabel; berguna saat tes tidak bisa hidup dalam transaksi.
  • Tes tidak boleh bergantung pada urutan atau pada data yang ditinggalkan tes lain.
  • --parallel membuat database terpisah per proses; pastikan tidak ada state global yang dibagi.

Tiga strategi

TraitCara kerjaKecepatanPakai saat
RefreshDatabaseMigrasi sekali, tiap tes dalam transaksi yang di-rollbackCepatDefault โ€” hampir selalu ini
DatabaseTruncationKosongkan tabel setelah tiap tesSedangKode yang memakai transaksinya sendiri, atau tes browser
DatabaseMigrationsmigrate:fresh sebelum tiap tesLambatSaat menguji migrasinya itu sendiri
// tests/Pest.php โ€” sekali untuk seluruh folder
pest()->extend(Tests\TestCase::class)
    ->use(RefreshDatabase::class)
    ->in('Feature');

Kenapa RefreshDatabase begitu cepat. Migrasi hanya berjalan sekali untuk seluruh suite. Setiap tes dibuka dengan BEGIN dan ditutup dengan ROLLBACK, jadi database kembali bersih tanpa satu pun tabel dibangun ulang. Konsekuensinya: kode yang menjalankan COMMIT sendiri atau membuka koneksi terpisah tidak akan terlindungi โ€” di situlah DatabaseTruncation masuk.

Assertion database

$this->assertDatabaseHas('artikel', [
    'slug'   => 'kabar-pagi',
    'status' => StatusArtikel::Terbit->value,
]);

$this->assertDatabaseMissing('artikel', ['slug' => 'draf-rahasia']);
$this->assertDatabaseCount('artikel', 3);
$this->assertSoftDeleted($artikel);
$this->assertNotSoftDeleted($artikel);
$this->assertModelMissing($artikel);

// Memastikan tidak ada query sama sekali โ€” misalnya karena cache bekerja
$this->expectsDatabaseQueryCount(2);

expectsDatabaseQueryCount() adalah cara menjadikan N+1 sebagai kegagalan tes. Tulis jumlah query yang kamu harapkan pada endpoint daftar; saat seseorang menambahkan relasi baru di template tanpa with(), angkanya melonjak dan tes berwarna merah. Ini pelengkap Model::preventLazyLoading() dari Fase 2, dan bekerja bahkan untuk query yang bukan berasal dari relasi.

Tes yang saling bergantung โ€” dan cara mencegahnya

// RAPUH โ€” bergantung pada isi seeder dan pada ID yang kebetulan 1
it('menampilkan artikel', function () {
    get('/artikel/1')->assertOk();
});

// KOKOH โ€” membuat sendiri apa yang dibutuhkannya
it('menampilkan artikel', function () {
    $artikel = Artikel::factory()->terbit()->create();

    get(route('artikel.show', $artikel))->assertOk();
});

Aturannya: setiap tes membuat sendiri seluruh data yang dibutuhkannya. Tes yang mengandalkan seeder akan patah saat seeder berubah, dan tes yang mengandalkan ID akan patah saat dijalankan paralel.

Seeder di dalam tes, kalau memang perlu

uses(RefreshDatabase::class);

beforeEach(function () {
    $this->seed(KategoriSeeder::class);      // hanya data referensi
});

Hanya seed data referensi. Kategori, wilayah, dan peran memang harus ada supaya foreign key valid. Data uji tetap dibuat oleh factory di dalam tes yang membutuhkannya, supaya jelas terbaca data mana yang relevan untuk perilaku yang sedang diuji.

Menjalankan paralel

composer require --dev brianium/paratest
php artisan test --parallel
php artisan test --parallel --recreate-databases

Laravel membuat satu database per proses (db_test_1, db_test_2, โ€ฆ). Yang bisa merusak paralelisme: berkas yang ditulis ke path tetap, cache bersama yang tidak dinamai unik, dan tes yang mengubah konfigurasi global. Kalau suite-mu hijau saat berurutan tapi merah saat paralel, salah satu dari tiga itu penyebabnya.

Latihan: tambahkan expectsDatabaseQueryCount() pada tes daftar artikelmu dengan angka yang benar. Lalu hapus with('penulis') dari controller-nya, jalankan tes, dan pastikan ia gagal dengan angka yang jauh lebih besar.

Rangkuman ini sengaja dipangkas ke bagian yang dipakai di roadmap. Buka sumber aslinya saat kamu butuh detail lengkap atau referensi parameter.