Testing adalah latihan disiplin yang memastikan kode berperilaku sesuai harapan sebelum sampai ke pengguna. Tanpa test, kita mengandalkan asumsi dan debug manual yang mahal ketika kode berkembang. Pada chapter ini kita akan membahas mengapa testing penting, tiga jenis test utama yang sering dijumpai, pola penulisan test Arrange-Act-Assert, dan bentuk test pyramid yang menjadi panduan distribusi jumlah test antar lapisan aplikasi.
Mengapa Testing Diperlukan #
Kode yang berjalan sekali belum tentu berjalan benar ketika dipakai berulang dengan input berbeda. Tanpa test otomatis, kita harus memverifikasi setiap perubahan secara manual — sebuah proses yang lambat, rentan lupa, dan tidak dapat diskalakan. Test otomatis menjadi jaring pengaman: setiap kali kode berubah, kita jalankan kembali test dan langsung tahu jika ada perilaku yang melenceng dari yang diharapkan.
Beberapa manfaat utama testing:
| Manfaat | Penjelasan |
|---|---|
| Regresi terdeteksi | Test lama gagal ketika perubahan baru merusak perilaku yang sudah berfungsi |
| Dokumentasi hidup | Nama test yang baik menjelaskan apa yang seharusnya dilakukan kode |
| Refactoring aman | Kita dapat mengubah struktur internal tanpa takut mengubah output |
| Desain lebih baik | Kode yang sulit diuji biasanya berarti coupling terlalu kuat |
Jenis Test: Unit, Integration, End-to-End #
Tidak semua test sama. Tiga kategori utama yang sering dijumpai:
| Jenis | Cakupan | Kecepatan | Contoh |
|---|---|---|---|
| Unit test | Satu function/class terisolasi | Sangat cepat (<10ms) | Test Kalkulator.tambah(2,3) == 5 |
| Integration test | Beberapa komponen bersamaan | Cepat (<1s) | Test Service + Repository in-memory |
| End-to-end (e2e) | Seluruh aplikasi dari UI hingga DB | Lambat (>1s) | Test request HTTP end-to-end |
Unit test fokus pada satu unit kecil — biasanya satu function atau class — dengan dependency diganti mock atau stub. Integration test menggabungkan beberapa komponen nyata untuk memverifikasi bahwa mereka bekerja sama. End-to-end test menjalankan seluruh alur dari pintu masuk aplikasi (HTTP request, klik tombol) sampai database dan kembali.
Pola Arrange-Act-Assert #
Pola Arrange-Act-Assert (AAA) membagi setiap test menjadi tiga bagian jelas. Arrange menyiapkan kondisi awal — objek yang dipakai, parameter input, state awal. Act memanggil fungsi yang sedang diuji dengan satu panggilan. Assert membandingkan hasil aktual dengan hasil yang diharapkan. Struktur ini membuat test mudah dibaca dan dipahami tanpa harus menebak langkah mana yang menyiapkan, mana yang mengeksekusi.
// testing_fundamentals.kt
// Mendemonstrasikan pola Arrange-Act-Assert (AAA) dan test pyramid
// dengan kode Kotlin murni (tanpa dependensi framework eksternal).
class Kalkulator {
fun tambah(a: Int, b: Int): Int = a + b
fun bagi(a: Int, b: Int): Int {
require(b != 0) { "Penyebut tidak boleh nol" }
return a / b
}
}
// Helper mini-assertion agar contoh tetap runnable tanpa JUnit.
fun cekHasil(nama: String, expected: Int, actual: Int) {
if (expected == actual) {
println("[LULUS] $nama => $actual")
} else {
println("[GAGAL] $nama => expected=$expected actual=$actual")
}
}
fun cekPengecualian(nama: String, blok: () -> Unit) {
try {
blok()
println("[GAGAL] $nama => tidak ada pengecualian")
} catch (e: IllegalArgumentException) {
println("[LULUS] $nama => ${e.message}")
}
}
fun main() {
// === Arrange-Act-Assert ===
// Arrange
val kalkulator = Kalkulator()
val a = 10
val b = 4
// Act
val hasil = kalkulator.tambah(a, b)
// Assert
cekHasil("tambah(10, 4)", 14, hasil)
// Skenario negatif: pembagian dengan nol
cekPengecualian("bagi(10, 0)") { kalkulator.bagi(10, 0) }
// === Test Pyramid ===
// Banyak unit test cepat di dasar, sedikit integration di tengah,
// sangat sedikit end-to-end di puncak.
println()
println("Pyramid: unit=${20}, integration=${4}, end_to_end=${1}")
}Output yang Dihasilkan:
[LULUS] tambah(10, 4) => 14
[LULUS] bagi(10, 0) => Penyebut tidak boleh nol
Pyramid: unit=20, integration=4, end_to_end=1Mari kita telaah bagian-bagian kunci contoh di atas:
- Class
Kalkulator: SUT (System Under Test) yang diuji. Memiliki methodtambahdanbagidengan kontrak jelas —bagimelemparIllegalArgumentExceptionsaat penyebut nol. cekHasil/cekPengecualian: helper assertion mini. Pada produksi kita akan pakaikotlin.testatau JUnit; di sini kita buat versi sederhana supaya file runnable tanpa library.- Bagian Arrange: tiga baris yang menyiapkan instance
kalkulatordan dua variabel inputadanb. - Bagian Act: satu baris
kalkulator.tambah(a, b)yang menghasilkanhasil. - Bagian Assert: panggilan
cekHasilyang membandingkanexpecteddanactual, lalucekPengecualianyang memastikan pengecualian yang tepat dilempar.
Test Pyramid #
Test pyramid adalah panduan distribusi test: paling banyak unit test di dasar, sedikit integration test di tengah, sangat sedikit end-to-end test di puncak. Alasannya murni praktis: unit test cepat dan stabil, e2e test lambat dan rapuh karena banyak dependensi eksternal. Jika piramida terbalik (banyak e2e, sedikit unit), build akan lambat dan sering gagal karena alasan di luar kendali kode.
Referensi Lanjutan #
- kotlin.test stdlib API
— rujukan resmi paket
kotlin.testuntuk assertion lintas platform yang dipakai sebagai fondasi pengujian - JUnit 5 user guide
— panduan resmi JUnit Jupiter yang menjelaskan anotasi
@Test, lifecycle, dan runner untuk pengujian JVM
Selanjutnya #
Setelah memahami pola AAA dan test pyramid, langkah berikutnya adalah memilih assertion library. Chapter kotlin-test akan memperkenalkan paket kotlin.test — lapisan assertion sederhana yang berjalan di multiplatform.