Di artikel sebelumnya, kita bahas kenapa testing penting. Sekarang saatnya membedah apa yang membuat sebuah test itu BAIK, bukan cuma "ada dan jalan". Ibaratnya, sebelum praktik menulis test pertama di artikel berikutnya, kita kenalan dulu dengan kosakata dan strukturnya — supaya test yang kita tulis nanti punya alasan di balik setiap barisnya.
Pola AAA: Arrange, Act, Assert
Hampir semua test yang baik, di bahasa dan framework apa pun, mengikuti struktur tiga bagian yang sama:
def test_verify_password_accepts_correct_password():
# Arrange — siapkan kondisi awal yang dibutuhkan
hashed = hash_password("supersecret123")
# Act — jalankan hal yang sedang diuji
result = verify_password("supersecret123", hashed)
# Assert — periksa hasilnya sesuai ekspektasi
assert result is True
assert yang saling terkait untuk memverifikasi perilaku itu.Pola ini penting bukan cuma soal rapi — test yang mengikuti AAA jauh lebih mudah dibaca ulang berbulan-bulan kemudian, dan lebih mudah didiagnosis begitu gagal, karena jelas bagian mana yang salah: persiapannya, aksinya, atau ekspektasinya.
Unit vs Integration vs E2E — Detail yang Membedakan
Di artikel sebelumnya kita sudah kenal testing pyramid. Sekarang lebih detail apa yang membedakan tiap lapisan, memakai contoh nyata dari task-tracker-api:
| Unit Test | Integration Test | E2E Test | |
|---|---|---|---|
| Contoh | verify_password("x", hash) diuji sendiri | POST /auth/login lewat TestClient, database SQLite sungguhan | Buka browser sungguhan, isi form login, klik submit |
| Kecepatan | Milidetik | Puluhan-ratusan milidetik | Detik-menit |
| Butuh database/network? | Tidak | Ya (biasanya versi test/in-memory) | Ya, sistem sungguhan |
| Kalau gagal, mudah tahu penyebabnya? | Sangat mudah — cuma satu fungsi | Cukup mudah — beberapa komponen | Sulit — banyak kemungkinan penyebab |
task-tracker-api kita nanti dipecah jadi tests/unit/ dan tests/integration/ — bukan cuma soal rapi, tapi supaya kita bisa menjalankan SUBSET yang cepat (pytest -m unit) saat butuh feedback instan sambil menulis kode, dan subset lengkap sebelum commit.
Test Doubles — Kosakata untuk "Pengganti" Dependency
Sering kali, kode yang mau kita uji bergantung pada sesuatu yang TIDAK ingin kita libatkan sungguhan saat test — database sungguhan, API eksternal, pengiriman email sungguhan. Test double adalah istilah umum untuk objek pengganti yang dipakai di test, menggantikan dependency asli. Ada beberapa jenis, dengan tujuan berbeda:
FakeRedis — implementasi in-memory yang benar-benar menghitung dan menyimpan counter, persis seperti Redis asli, cuma tidak perlu proses Redis sungguhan berjalan.Perbedaan istilah ini kadang dipakai agak longgar di percakapan sehari-hari (banyak orang bilang "mock" untuk semua jenis di atas), tapi memahami bedanya membantu memilih tool yang tepat: kalau cuma butuh dependency "diam saja dan tidak mengganggu", stub sudah cukup. Kalau perlu MEMBUKTIKAN sesuatu benar-benar dipanggil, itu kasusnya mock.
Prinsip FIRST — Ciri Test yang Sehat
Kerangka lain yang berguna untuk menilai kualitas test:
assert), tidak perlu manusia membaca output dan menyimpulkan sendiri.Kita akan kembali ke prinsip Independent dan Repeatable ini secara konkret di artikel berikutnya, saat membahas kenapa setiap integration test butuh database yang benar-benar bersih dan terisolasi, bukan database bersama yang dipakai berulang antar test.