Dokumentasi contoh pemakaian biasanya ditulis terpisah dari kode, sehingga cepat basi: fungsi berubah, contoh di README tidak ikut berubah, dan pembaca menyalin kode yang sudah tidak benar lagi. Go menyatukan keduanya lewat example test: fungsi ExampleXxx pada berkas _test.go yang keluarannya diverifikasi setiap kali go test berjalan. Contoh yang gagal mengikuti perilaku kode akan membuat test gagal, jadi dokumentasi terpaksa selalu segar. Pada chapter ini kita akan menulis contoh terverifikasi untuk fungsi FormatRupiah dan tipe Keranjang, termasuk aturan penamaan serta pencocokan keluarannya.

Konsep Example Test #

Example test adalah fungsi bernama ExampleXxx tanpa parameter, diletakkan di berkas _test.go, dan ditutup komentar // Output: yang memuat keluaran yang diharapkan. Ketika go test berjalan, framework menjalankan fungsi tersebut, menangkap tulisannya ke standard output, lalu membandingkan hasilnya dengan isi komentar. Pencocokan hanya mengabaikan spasi di awal dan akhir seluruh keluaran; baris demi baris di tengahnya harus sama persis.

Contoh tanpa komentar // Output: hanya dikompilasi dan tidak dijalankan — bentuk ini cocok untuk cuplikan dokumentasi yang memang tidak menghasilkan keluaran berarti. Alat dokumentasi seperti situs pkg.go.dev kemudian menampilkan contoh-contoh ini tepat di sebelah fungsi atau tipe yang dirujuknya, sehingga pembaca dokumentasi melihat kode yang dijamin terkompilasi dan (bila ber-output) terverifikasi.

Kode yang Didokumentasikan #

Kita memakai dua target dokumentasi: fungsi FormatRupiah yang memformat angka menjadi teks rupiah, dan tipe Keranjang beserta method Ringkasan. Simpan kode berikut sebagai rupiah.go:

go
package main

import (
	"fmt"
	"strconv"
	"strings"
)

// FormatRupiah memformat bilangan bulat menjadi teks rupiah dengan pemisah
// ribuan, contoh 150000 menjadi "Rp150.000" dan -50000 menjadi "-Rp50.000".
func FormatRupiah(nilai int) string {
	negatif := nilai < 0
	if negatif {
		nilai = -nilai
	}
	digits := strconv.Itoa(nilai)
	var b strings.Builder
	sisa := len(digits)
	for _, d := range digits {
		b.WriteRune(d)
		sisa--
		if sisa > 0 && sisa%3 == 0 {
			b.WriteByte('.')
		}
	}
	hasil := b.String()
	if negatif {
		return "-Rp" + hasil
	}
	return "Rp" + hasil
}

// Keranjang menyimpan daftar barang yang dibeli oleh satu pembeli.
type Keranjang struct {
	atasNama string
	barang   []string
}

// NewKeranjang membuat keranjang baru atas nama pembeli.
func NewKeranjang(atasNama string) *Keranjang {
	return &Keranjang{atasNama: atasNama}
}

// Tambah memasukkan satu barang ke dalam keranjang.
func (k *Keranjang) Tambah(barang string) {
	k.barang = append(k.barang, barang)
}

// Ringkasan menghasilkan satu baris deskripsi isi keranjang.
func (k *Keranjang) Ringkasan() string {
	return fmt.Sprintf("%s membeli %d barang: %s", k.atasNama, len(k.barang), strings.Join(k.barang, ", "))
}

func main() {
	fmt.Println(FormatRupiah(150000))
	fmt.Println(FormatRupiah(-50000))
	k := NewKeranjang("Budi")
	k.Tambah("buku tulis")
	k.Tambah("pulpen")
	fmt.Println(k.Ringkasan())
}

Jalankan berkas tersebut dari folder chapter:

bash
go run rupiah.go

Output yang Dihasilkan:

text
Rp150.000
-Rp50.000
Budi membeli 2 barang: buku tulis, pulpen

Mari kita telaah bagian-bagian utamanya:

  1. Baris 11-31 (func FormatRupiah): mengubah nilai absolut menjadi teks, lalu menyisipkan pemisah . setiap tiga digit dari kanan lewat penghitung sisa pada baris 18-24.
  2. Baris 27-30: cabang nilai negatif mengembalikan hasil dengan awalan -Rp agar tanda minus berada sebelum mata uang.
  3. Baris 34-37 (type Keranjang): struct dengan field tidak diekspor, sehingga pembangunannya hanya melalui NewKeranjang di baris 40-42.
  4. Baris 45-52 (Tambah dan Ringkasan): method pointer yang menyimpan barang dan merangkai deskripsi isi keranjang; keduanya menjadi bahan contoh method pada chapter ini.

Berkas rupiah_test.go berisi satu unit test dan empat contoh dengan variasi penamaan:

go
package main

import (
	"fmt"
	"testing"
)

func TestFormatRupiah(t *testing.T) {
	uji := []struct {
		masuk      int
		diharapkan string
	}{
		{0, "Rp0"},
		{500, "Rp500"},
		{150000, "Rp150.000"},
		{-50000, "-Rp50.000"},
	}
	for _, u := range uji {
		if got := FormatRupiah(u.masuk); got != u.diharapkan {
			t.Errorf("FormatRupiah(%d) = %q, diharapkan %q", u.masuk, got, u.diharapkan)
		}
	}
}

// ExampleFormatRupiah adalah contoh pemakaian paling dasar.
// Komentar // Output: membuat go test memverifikasi keluarannya.
func ExampleFormatRupiah() {
	fmt.Println(FormatRupiah(1500000))
	fmt.Println(FormatRupiah(25000))
	fmt.Println(FormatRupiah(-7500))
	// Output:
	// Rp1.500.000
	// Rp25.000
	// -Rp7.500
}

// ExampleFormatRupiah_negatif adalah contoh bersuffix untuk kasus nilai
// negatif; suffix harus diawali huruf kecil.
func ExampleFormatRupiah_negatif() {
	fmt.Println(FormatRupiah(-1234567))
	// Output:
	// -Rp1.234.567
}

// ExampleKeranjang_Ringkasan mencontohkan pemakaian method Ringkasan milik
// tipe Keranjang; nama contoh mengikuti pola ExampleT_Method.
func ExampleKeranjang_Ringkasan() {
	k := NewKeranjang("Siti")
	k.Tambah("kaos")
	k.Tambah("topi")
	fmt.Println(k.Ringkasan())
	// Output:
	// Siti membeli 2 barang: kaos, topi
}

// ExampleNewKeranjang tidak memiliki komentar // Output:, sehingga hanya
// dikompilasi sebagai dokumentasi tanpa verifikasi keluaran.
func ExampleNewKeranjang() {
	k := NewKeranjang("Budi")
	k.Tambah("beras 5 kg")
}

Jalankan seluruhnya dari folder chapter:

bash
go test -v ./...

Output yang Dihasilkan:

text
=== RUN   TestFormatRupiah
--- PASS: TestFormatRupiah (0.00s)
=== RUN   ExampleFormatRupiah
--- PASS: ExampleFormatRupiah (0.00s)
=== RUN   ExampleFormatRupiah_negatif
--- PASS: ExampleFormatRupiah_negatif (0.00s)
=== RUN   ExampleKeranjang_Ringkasan
--- PASS: ExampleKeranjang_Ringkasan (0.00s)
PASS
ok  	tutorial-website/content/go/testing/example-test	0.006s

Pada berkas tersebut terdapat empat variasi contoh:

  1. Baris 27-35 (ExampleFormatRupiah): contoh dasar untuk fungsi FormatRupiah. Tiga baris fmt.Println diharuskan menghasilkan tepat tiga baris keluaran yang tertulis setelah // Output:.
  2. Baris 39-43 (ExampleFormatRupiah_negatif): contoh bersuffix untuk kasus khusus nilai negatif; suffix diawali huruf kecil.
  3. Baris 47-54 (ExampleKeranjang_Ringkasan): contoh untuk method, memakai pola nama ExampleT_Method sehingga terhubung ke method Ringkasan milik Keranjang.
  4. Baris 58-61 (ExampleNewKeranjang): contoh tanpa // Output: — perhatikan bahwa fungsi ini tidak muncul pada output go test -v di atas karena hanya dikompilasi, tidak dijalankan.

Aturan Penamaan Contoh #

Nama fungsi menentukan contoh terhubung ke bagian mana dalam dokumentasi:

Nama contohMenunjukkan contoh untuk
Example()Package secara keseluruhan
ExampleFormatRupiah()Fungsi FormatRupiah
ExampleKeranjang()Tipe Keranjang
ExampleKeranjang_Ringkasan()Method Ringkasan milik Keranjang
ExampleFormatRupiah_negatif()Kasus khusus, suffix diawali huruf kecil

Ketika urutan baris memang tidak menentu (misalnya keluaran dari iterasi map), tersedia komentar // Unordered output: yang mencocokkan baris apa pun urutannya. Untuk keluaran yang benar-benar bervariasi seperti waktu atau alamat memori, jangan paksa menjadi contoh terverifikasi; cukup tulis sebagai contoh tanpa output.

Referensi #

Dokumentasi yang ikut teruji membuat contoh kode selalu dapat dipercaya, dan coverage pada chapter berikutnya mengukur dari sisi berlawanan: seberapa besar bagian kode produksi yang benar-benar pernah dieksekusi oleh test kita.

Berkas Sumber

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

rupiah_test.go

Unduh berkas
go
package main

import (
	"fmt"
	"testing"
)

func TestFormatRupiah(t *testing.T) {
	uji := []struct {
		masuk      int
		diharapkan string
	}{
		{0, "Rp0"},
		{500, "Rp500"},
		{150000, "Rp150.000"},
		{-50000, "-Rp50.000"},
	}
	for _, u := range uji {
		if got := FormatRupiah(u.masuk); got != u.diharapkan {
			t.Errorf("FormatRupiah(%d) = %q, diharapkan %q", u.masuk, got, u.diharapkan)
		}
	}
}

// ExampleFormatRupiah adalah contoh pemakaian paling dasar.
// Komentar // Output: membuat go test memverifikasi keluarannya.
func ExampleFormatRupiah() {
	fmt.Println(FormatRupiah(1500000))
	fmt.Println(FormatRupiah(25000))
	fmt.Println(FormatRupiah(-7500))
	// Output:
	// Rp1.500.000
	// Rp25.000
	// -Rp7.500
}

// ExampleFormatRupiah_negatif adalah contoh bersuffix untuk kasus nilai
// negatif; suffix harus diawali huruf kecil.
func ExampleFormatRupiah_negatif() {
	fmt.Println(FormatRupiah(-1234567))
	// Output:
	// -Rp1.234.567
}

// ExampleKeranjang_Ringkasan mencontohkan pemakaian method Ringkasan milik
// tipe Keranjang; nama contoh mengikuti pola ExampleT_Method.
func ExampleKeranjang_Ringkasan() {
	k := NewKeranjang("Siti")
	k.Tambah("kaos")
	k.Tambah("topi")
	fmt.Println(k.Ringkasan())
	// Output:
	// Siti membeli 2 barang: kaos, topi
}

// ExampleNewKeranjang tidak memiliki komentar // Output:, sehingga hanya
// dikompilasi sebagai dokumentasi tanpa verifikasi keluaran.
func ExampleNewKeranjang() {
	k := NewKeranjang("Budi")
	k.Tambah("beras 5 kg")
}

rupiah.go

Unduh berkas
go
package main

import (
	"fmt"
	"strconv"
	"strings"
)

// FormatRupiah memformat bilangan bulat menjadi teks rupiah dengan pemisah
// ribuan, contoh 150000 menjadi "Rp150.000" dan -50000 menjadi "-Rp50.000".
func FormatRupiah(nilai int) string {
	negatif := nilai < 0
	if negatif {
		nilai = -nilai
	}
	digits := strconv.Itoa(nilai)
	var b strings.Builder
	sisa := len(digits)
	for _, d := range digits {
		b.WriteRune(d)
		sisa--
		if sisa > 0 && sisa%3 == 0 {
			b.WriteByte('.')
		}
	}
	hasil := b.String()
	if negatif {
		return "-Rp" + hasil
	}
	return "Rp" + hasil
}

// Keranjang menyimpan daftar barang yang dibeli oleh satu pembeli.
type Keranjang struct {
	atasNama string
	barang   []string
}

// NewKeranjang membuat keranjang baru atas nama pembeli.
func NewKeranjang(atasNama string) *Keranjang {
	return &Keranjang{atasNama: atasNama}
}

// Tambah memasukkan satu barang ke dalam keranjang.
func (k *Keranjang) Tambah(barang string) {
	k.barang = append(k.barang, barang)
}

// Ringkasan menghasilkan satu baris deskripsi isi keranjang.
func (k *Keranjang) Ringkasan() string {
	return fmt.Sprintf("%s membeli %d barang: %s", k.atasNama, len(k.barang), strings.Join(k.barang, ", "))
}

func main() {
	fmt.Println(FormatRupiah(150000))
	fmt.Println(FormatRupiah(-50000))
	k := NewKeranjang("Budi")
	k.Tambah("buku tulis")
	k.Tambah("pulpen")
	fmt.Println(k.Ringkasan())
}