September 28, 2026
Dasar Testing.
Konsep dasar automated testing: unit, integration, dan end-to-end test, piramida testing, pola Arrange-Act-Assert, test double (mock, stub, spy, fake), serta cara menulis test yang andal dan mudah dirawat.
Automated test adalah kode yang memeriksa kode lain. Tujuannya bukan sekadar “coverage tinggi”, melainkan kepercayaan diri: berani refactor, upgrade dependency, atau deploy hari Jumat tanpa takut ada yang rusak diam-diam. Catatan ini membahas konsep yang berlaku di bahasa apa pun; implementasinya ada di catatan Vitest , Pest untuk Laravel , dan Playwright .
1. Jenis Test
| Jenis | Menguji | Kecepatan | Contoh |
|---|---|---|---|
| Unit | Satu fungsi/class secara terisolasi | Milidetik | hitungDiskon(100000, 10) → 90000 |
| Integration | Beberapa bagian bekerja bersama (kode + DB, kode + API) | Puluhan–ratusan ms | Endpoint POST /orders menyimpan ke database |
| End-to-end (E2E) | Aplikasi utuh dari sudut pandang user, lewat browser | Detik | Login → tambah ke keranjang → checkout |
Istilah lain yang sering muncul:
| Istilah | Arti |
|---|---|
| Feature test | Istilah Laravel untuk integration test yang memanggil HTTP request |
| Component test | Merender satu komponen UI dan berinteraksi dengannya |
| Smoke test | Test kecil untuk memastikan hal paling dasar jalan (halaman utama 200) |
| Regression test | Test yang ditulis setelah bug ditemukan, agar bug itu tidak kembali |
| Snapshot test | Membandingkan output dengan hasil yang tersimpan sebelumnya |
2. Piramida Testing
▲ sedikit, lambat, mahal, paling realistis
/ \
/ E2E\
/-------\
/Integrat.\
/-----------\
/ Unit \
/_______________\
banyak, cepat, murah, paling terisolasi
Idenya: banyak unit test (murah dan cepat), sedang integration test, dan sedikit E2E untuk alur kritis (login, pembayaran). Makin ke atas, test makin realistis tapi makin lambat dan rapuh.
Varian modern seperti testing trophy menekankan bahwa integration test memberi rasio “kepercayaan per biaya” terbaik untuk aplikasi web. Dokumentasi Laravel pun menyatakan sebagian besar test sebaiknya berupa feature test. Kesimpulan praktisnya:
- Logika murni (kalkulasi, parsing, validasi) → unit test.
- Endpoint, query, dan komponen UI → integration/feature test.
- 3–10 alur bisnis terpenting → E2E.
3. Pola Arrange–Act–Assert (AAA)
Setiap test yang baik punya tiga bagian jelas:
// hitungTotal.ts
export function hitungTotal(items: { harga: number; qty: number }[], diskonPersen = 0) {
const subtotal = items.reduce((t, i) => t + i.harga * i.qty, 0);
return Math.round(subtotal * (1 - diskonPersen / 100));
}
// hitungTotal.test.ts
import { describe, expect, it } from "vitest";
import { hitungTotal } from "./hitungTotal";
describe("hitungTotal", () => {
it("menerapkan diskon persen pada subtotal", () => {
// Arrange — siapkan data
const items = [
{ harga: 50000, qty: 2 },
{ harga: 25000, qty: 1 },
];
// Act — jalankan satu aksi
const total = hitungTotal(items, 10);
// Assert — periksa hasil
expect(total).toBe(112500);
});
it("mengembalikan 0 untuk keranjang kosong", () => {
expect(hitungTotal([])).toBe(0);
});
});
Padanannya di BDD adalah Given–When–Then. Aturan penting: satu test = satu perilaku. Nama test menjelaskan perilaku itu dalam kalimat, sehingga laporan gagal langsung terbaca (“hitungTotal › menerapkan diskon persen pada subtotal”).
4. Test Double: Mock, Stub, Spy, Fake
Unit test harus cepat dan deterministik, jadi dependensi yang lambat atau tak terduga (API luar, email, waktu, random) diganti dengan test double.
| Jenis | Fungsi | Contoh |
|---|---|---|
| Stub | Mengembalikan jawaban tetap | getKurs() selalu 15500 |
| Spy | Mencatat pemanggilan fungsi asli/pengganti | “apakah kirimEmail dipanggil 1×?” |
| Mock | Stub + ekspektasi tentang cara dipanggil | Harus dipanggil dengan argumen X |
| Fake | Implementasi ringan yang benar-benar bekerja | Repository in-memory, Mail::fake() di Laravel |
Contoh dengan dependency injection (paling mudah di-test):
type Mailer = { kirim(to: string, subjek: string): Promise<void> };
export async function daftarUser(email: string, mailer: Mailer) {
// ... simpan user
await mailer.kirim(email, "Selamat datang!");
return { email };
}
import { expect, it, vi } from "vitest";
import { daftarUser } from "./daftarUser";
it("mengirim email sambutan", async () => {
const mailer = { kirim: vi.fn().mockResolvedValue(undefined) };
await daftarUser("[email protected]", mailer);
expect(mailer.kirim).toHaveBeenCalledOnce();
expect(mailer.kirim).toHaveBeenCalledWith("[email protected]", "Selamat datang!");
});
Kapan jangan mock
- Jangan mock yang Anda uji. Jika semua dependensi di-mock, test hanya membuktikan mock-nya benar.
- Utamakan fake daripada mock untuk hal seperti database — database test sungguhan (SQLite in-memory, container) jauh lebih meyakinkan.
- Mock di batas sistem: HTTP ke pihak ketiga, email, payment gateway, waktu (
vi.useFakeTimers()), random.
5. Ciri Test yang Baik (FIRST)
| Huruf | Prinsip | Artinya |
|---|---|---|
| F | Fast | Suite unit selesai dalam detik, agar dijalankan sering |
| I | Isolated | Tidak bergantung urutan atau hasil test lain |
| R | Repeatable | Hasil sama di laptop, CI, jam berapa pun |
| S | Self-validating | Lulus/gagal jelas, tanpa cek manual log |
| T | Timely | Ditulis bersamaan dengan kode (atau sebelumnya — TDD) |
Selain itu: uji perilaku, bukan implementasi. Test yang memeriksa state internal atau urutan pemanggilan private method akan patah setiap refactor, padahal perilaku tidak berubah.
TDD singkat
Siklus Red → Green → Refactor: tulis test yang gagal, tulis kode minimal agar lulus, lalu rapikan. Tidak wajib, tapi sangat efektif untuk logika bisnis dengan aturan jelas dan untuk memperbaiki bug (tulis test yang mereproduksi bug dulu).
6. Menjalankan Test di CI
Test paling berharga jika dijalankan otomatis di setiap push/PR. Pipeline minimal: install → lint → type-check → unit/integration → E2E (opsional di branch utama). Contoh GitHub Actions ada di catatan TypeScript di Proyek Nyata . Branch protection yang mewajibkan CI hijau sebelum merge adalah kebiasaan yang sangat layak diadopsi.
Kesalahan Umum
- Mengejar coverage 100%. Coverage mengukur baris yang dieksekusi, bukan yang diverifikasi. Test tanpa assertion tetap menaikkan coverage.
- Test saling bergantung. Test B lulus hanya jika test A jalan dulu → gagal acak saat dijalankan paralel atau terfilter.
- Over-mocking. Semua di-mock, test hijau, produksi tetap rusak.
- Test yang flaky dibiarkan. Test yang kadang gagal membuat tim terbiasa mengabaikan merah. Perbaiki atau karantina segera.
- Bergantung waktu/random nyata.
new Date()danMath.random()membuat hasil berubah; kendalikan dengan fake timer atau injeksi. - Nama test tidak deskriptif (
test1,it works). Saat gagal, tidak ada yang tahu apa yang rusak. - Terlalu banyak E2E. Suite E2E 40 menit membuat developer berhenti menjalankannya.
Ringkasan
- Unit untuk logika murni, integration/feature untuk sebagian besar aplikasi, E2E untuk alur kritis.
- Struktur setiap test dengan Arrange–Act–Assert, satu perilaku per test.
- Mock di batas sistem; utamakan fake dan database test sungguhan.
- Uji perilaku, bukan implementasi, dan jalankan semuanya di CI.

Hey! I’m Fanny, the software engineer tending to this digital garden. You can read more about me, or subscribe by email.