Testing, Debugging, dan Kualitas Kode · 2/7
Unit test dengan Vitest
describe, it, expect — dan cara memilih kasus yang benar-benar bisa menangkap kesalahan.
Baca 30 menit
Setelah pelajaran ini kamu bisa
- Menulis test dengan describe, it, dan expect
- Memilih matcher yang memberi pesan kegagalan paling jelas
- Memilih kasus test yang benar-benar bisa menangkap kesalahan
- Menguji kode asinkron dan error yang diharapkan
Framework test itu jauh lebih kecil dari kelihatannya. Tiga function, sebuah daftar, dan sebuah perbandingan. Membuatnya butuh sekitar tiga puluh baris, dan setelahnya tidak ada lagi yang terasa misterius soal testing.
Framework test yang berfungsi, lalu test sungguhan dijalankan lewatnya. Ini benar-benar cara kerja vitest di dalamnya.
Hasil
Tekan Jalankan untuk melihat hasilnya.
Ini jalan di browser kamu, di dalam sandbox. Apa pun yang kamu tulis di sini tidak bisa merusak situs.
Itu seluruh idenya. it menangkap error yang dilempar lalu mencatat kegagalan; expect melempar saat perbandingannya gagal. Setiap framework test yang akan kamu pakai adalah ini, plus pelaporan, pemantauan, dan paralelisme.
Yang sungguhan
import { describe, expect, it } from "vitest";
import { interpolate } from "./interpolate";
describe("interpolate", () => {
it("substitutes a single placeholder", () => {
expect(interpolate("{count} modules", { count: 12 })).toBe("12 modules");
});
it("leaves unknown placeholders verbatim so the gap is visible", () => {
expect(interpolate("{count} modules", {})).toBe("{count} modules");
});
it("does not treat a zero value as missing", () => {
expect(interpolate("{done} done", { done: 0 })).toBe("0 done");
});
});features/i18n/interpolate.test.ts dari proyek ini, tanpa diedit. Perhatikan nama test-nya: masing-masing menyatakan sebuah aturan, jadi kegagalannya terbaca sebagai "aturan ini rusak".| Matcher | Untuk |
|---|---|
toBe(x) | Primitive dan identitas. Memakai Object.is. |
toEqual(x) | Perbandingan struktural mendalam untuk object dan array |
toThrow(msg) | Function yang harus melempar error. Kirim function-nya, bukan pemanggilannya. |
toHaveLength(n) | Kegagalannya lebih jelas daripada .length dengan toBe |
toContain(x) | Sebuah item array atau substring |
toBeDefined() | Bukan undefined — lebih baik daripada toBe(undefined) yang dinegasikan |
await expect(p).resolves.toBe(x) | Nilai hasil resolve sebuah promise |
await expect(p).rejects.toThrow() | Promise yang harus reject |
Memilih kasus
Satu test per function bukan sebuah suite. Kasus yang menemukan bug adalah kasus di batas dan kasus yang mengejutkan.
- Kasus normal. Satu sudah cukup.
- Kosong. String kosong, array kosong, nol, tanpa row.
- Batas. Tepat di batasnya, dan satu di masing-masing sisinya.
- Type yang salah.
null,undefined, angka di tempat yang seharusnya string. - Jebakan falsy.
0dan""adalah dua yang merusak fallback||. - Bug yang baru kamu perbaiki. Selalu. Itulah yang mencegahnya kembali.
Async dan error
// A resolved value.
it("hashes a password", async () => {
const hash = await hashPassword("secret123");
expect(hash).not.toContain("secret123");
});
// A rejection, without a try/catch in the test.
it("returns false for a malformed stored hash instead of throwing", async () => {
await expect(verifyPassword("anything", "not-a-hash")).resolves.toBe(false);
});
// Table-driven: one assertion, many inputs. Note the label in expect(),
// which makes the failure say WHICH input broke.
it("rejects every malformed hash shape", async () => {
for (const stored of ["", "not-a-hash", "scrypt$16384$8$1$aa", "$$$$$"]) {
await expect(verifyPassword("x", stored), stored).resolves.toBe(false);
}
});expect adalah label. Di dalam loop, itulah pembeda antara "salah satu dari lima input gagal" dan mengetahui yang mana.Tugas praktik
Tulis features/lesson/slugify.ts dengan function slugify dari runner-nya, dan slugify.test.ts di sebelahnya yang mencakup setiap kasus di daftar periksa di atas. Jalankan bun run test slugify. Lalu sengaja rusak function-nya dan pastikan pesan kegagalannya mengidentifikasi aturan mana yang rusak.
Hasil yang diharapkan
Enam atau tujuh test lolos, dan kegagalan yang jelas saat kamu merusaknya.