Semakin besar program, semakin mudah satu perubahan merusak perilaku di tempat lain tanpa terasa. Unit test menjawab masalah tersebut: program kecil yang memanggil fungsi Anda, membandingkan hasilnya dengan nilai yang diharapkan, lalu melaporkan setiap ketidakcocokan secara otomatis. Go membawa budaya ini sejak awal — perintah go test dan package testing tersedia bawaan, tanpa framework pihak ketiga. Pada chapter ini kita menulis test pertama untuk kalkulator mini, menjalankannya dengan beberapa variasi perintah, lalu membedah outputnya ketika lulus maupun gagal.

Kode produksi kita berisi dua fungsi aritmetika sederhana pada berkas kalkulator.go:

go
package main

// Tambah mengembalikan hasil penjumlahan a dan b.
func Tambah(a, b int) int {
	return a + b
}

// Kali mengembalikan hasil perkalian a dan b.
func Kali(a, b int) int {
	return a * b
}

Test ditulis pada berkas terpisah berakhiran _test.go. Berkas test berada di package yang sama dengan kode produksi — di sini keduanya package main — sehingga test dapat memanggil Tambah dan Kali langsung. Perintah go build mengabaikan berkas _test.go; hanya go test yang mengompilasi berkas tersebut ke dalam binary test. Berikut isi kalkulator_test.go:

go
package main

import "testing"

func TestTambah(t *testing.T) {
	got := Tambah(2, 3)
	want := 5
	if got != want {
		t.Errorf("Tambah(2, 3) = %d; want %d", got, want)
	}
}

func TestKali(t *testing.T) {
	got := Kali(4, 6)
	want := 24
	if got != want {
		t.Errorf("Kali(4, 6) = %d; want %d", got, want)
	}
}

Mari kita telaah baris demi baris berkas test di atas:

  1. Baris 1 (package main): menempatkan berkas test pada package yang sama dengan kalkulator.go, sehingga seluruh fungsi produksi dapat dipanggil langsung.
  2. Baris 3 (import "testing"): mengimpor package testing yang menyediakan tipe testing.T sebagai perantara pelaporan kegagalan.
  3. Baris 5 (func TestTambah(t *testing.T)): mendeklarasikan fungsi test. Nama fungsi harus diawali Test diikuti huruf kapital agar go test menjalankannya; parameter t bertipe *testing.T.
  4. Baris 6-7 (got dan want): variabel got menyimpan hasil aktual Tambah(2, 3), variabel want menyimpan nilai yang diharapkan. Pemisahan keduanya membuat pesan kegagalan mudah dibaca.
  5. Baris 8-10 (if + t.Errorf): ketika got tidak sama dengan want, t.Errorf mencatat kegagalan dengan format verb %d — dan test tetap berlanjut sampai fungsi selesai.
  6. Baris 13-19 (TestKali): mengulangi pola yang sama untuk Kali. Satu fungsi produksi diuji satu fungsi test terpisah agar kegagalan keduanya tidak saling menyamarkan.

Menjalankan go test #

Dari direktori chapter, jalankan:

bash
go test -v ./...

Output yang Dihasilkan:

text
=== RUN   TestTambah
--- PASS: TestTambah (0.00s)
=== RUN   TestKali
--- PASS: TestKali (0.00s)
PASS

Flag -v meminta go test mencetak setiap test yang berjalan: baris === RUN menandai awal test, --- PASS menandai test yang lulus, dan angka (0.00s) adalah durasi test tersebut. Tanpa -v, go test hanya mencetak satu baris ringkasan per package; pada proyek situs ini barisnya berbunyi ok tutorial-website/content/go/testing/unit-test 0.002s.

Menjalankan go test dua kali tanpa perubahan kode menghasilkan tanda (cached) karena Go menyimpan hasil test pada cache. Gunakan go clean -testcache atau flag -count=1 untuk memaksa eksekusi ulang.

Menyaring Test dengan -run #

Flag -run menerima pola regular expression dan hanya menjalankan test yang namanya cocok:

bash
go test -v -run TestTambah ./...

Output yang Dihasilkan:

text
=== RUN   TestTambah
--- PASS: TestTambah (0.00s)
PASS

Hanya TestTambah yang berjalan; TestKali tidak muncul. Pola -run TestTambah juga mencocokkan nama berawalan sama seperti TestTambahNegatif, jadi tambahkan pengikat seperti "^TestTambah$" bila ingin cocokan persis. Kombinasi -run dan -v adalah alat utama mempercepat siklus edit-lalu-uji.

Membaca Output Ketika Test Gagal #

Bentuk output kegagalan paling mudah dipahami lewat eksperimen kecil. Ubah sementara baris 5 kalkulator.go dari return a + b menjadi return a + b + 1, jalankan go test -v ./..., lalu kembalikan. Fungsi Tambah kini mengembalikan 6 untuk input 2 dan 3, sehingga TestTambah gagal:

Output yang Dihasilkan:

text
=== RUN   TestTambah
    kalkulator_test.go:9: Tambah(2, 3) = 6; want 5
--- FAIL: TestTambah (0.00s)
=== RUN   TestKali
--- PASS: TestKali (0.00s)
FAIL

Baris kalkulator_test.go:9: menunjukkan berkas dan nomor baris pemanggilan t.Errorf — baris 9, tempat t.Errorf berada di dalam TestTambah. TestKali tetap berjalan setelah kegagalan tersebut karena t.Errorf hanya mencatat masalah tanpa menghentikan eksekusi. Ringkasannya:

Kondisi hasilBaris ringkasanExit status
Semua test lulusok <path-paket> <durasi>0
Ada test gagalFAIL <path-paket> <durasi>1
Kode tidak berubah sejak run laluok <path-paket> (cached)0

Exit status 1 membuat go test gagal pada pipeline CI maupun skrip build, sehingga test rusak langsung terlihat sebelum rilis.

t.Errorf vs t.Fatalf #

t.Errorf mencatat pesan lalu melanjutkan eksekusi test; t.Fatalf mencatat pesan lalu menghentikan fungsi test saat itu juga. Perbedaannya terlihat pada fragmen berikut:

go
func TestHitung(t *testing.T) {
	got, err := Hitung("2+3")
	if err != nil {
		// hasil akhir tidak bisa dipercaya: hentikan test.
		t.Fatalf("Hitung galat: %v", err)
	}
	if got != 5 {
		// pemeriksaan lain masih relevan: cukup catat.
		t.Errorf("got %d; want 5", got)
	}
}
MetodePerilaku setelah kegagalanKapan dipakai
t.ErrorfMencatat galat, test berlanjutPemeriksaan yang saling independen
t.FatalfMencatat galat, test berhentiLangkah berikutnya tidak bermakna tanpa hasil tahap awal

Sejauh ini satu blok pemeriksaan menangani satu kasus. Fungsi dengan banyak kasus masukan akan membuat pola ini memanjang lewat salin-tempel; chapter Table-Driven Test memperkenalkan pola tabel yang merapikannya. Perintah go test -cover ./... juga layak dicoba untuk mengukur persentase kode yang tersentuh test — dibahas tuntas pada chapter Coverage .

Referensi #

Berkas Sumber

Berkas pendukung halaman ini dapat diunduh dan dijalankan langsung sesuai penjelasan di atas.

kalkulator_test.go

Unduh berkas
go
package main

import "testing"

func TestTambah(t *testing.T) {
	got := Tambah(2, 3)
	want := 5
	if got != want {
		t.Errorf("Tambah(2, 3) = %d; want %d", got, want)
	}
}

func TestKali(t *testing.T) {
	got := Kali(4, 6)
	want := 24
	if got != want {
		t.Errorf("Kali(4, 6) = %d; want %d", got, want)
	}
}

kalkulator.go

Unduh berkas
go
package main

// Tambah mengembalikan hasil penjumlahan a dan b.
func Tambah(a, b int) int {
	return a + b
}

// Kali mengembalikan hasil perkalian a dan b.
func Kali(a, b int) int {
	return a * b
}