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:
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:
go run rupiah.goOutput yang Dihasilkan:
Rp150.000
-Rp50.000
Budi membeli 2 barang: buku tulis, pulpenMari kita telaah bagian-bagian utamanya:
- Baris 11-31 (
func FormatRupiah): mengubah nilai absolut menjadi teks, lalu menyisipkan pemisah.setiap tiga digit dari kanan lewat penghitungsisapada baris 18-24. - Baris 27-30: cabang nilai negatif mengembalikan hasil dengan awalan
-Rpagar tanda minus berada sebelum mata uang. - Baris 34-37 (
type Keranjang): struct dengan field tidak diekspor, sehingga pembangunannya hanya melaluiNewKeranjangdi baris 40-42. - Baris 45-52 (
TambahdanRingkasan): method pointer yang menyimpan barang dan merangkai deskripsi isi keranjang; keduanya menjadi bahan contoh method pada chapter ini.
Menulis Example Terverifikasi #
Berkas rupiah_test.go berisi satu unit test dan empat contoh dengan variasi penamaan:
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:
go test -v ./...Output yang Dihasilkan:
=== 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.006sPada berkas tersebut terdapat empat variasi contoh:
- Baris 27-35 (
ExampleFormatRupiah): contoh dasar untuk fungsiFormatRupiah. Tiga barisfmt.Printlndiharuskan menghasilkan tepat tiga baris keluaran yang tertulis setelah// Output:. - Baris 39-43 (
ExampleFormatRupiah_negatif): contoh bersuffix untuk kasus khusus nilai negatif; suffix diawali huruf kecil. - Baris 47-54 (
ExampleKeranjang_Ringkasan): contoh untuk method, memakai pola namaExampleT_Methodsehingga terhubung ke methodRingkasanmilikKeranjang. - Baris 58-61 (
ExampleNewKeranjang): contoh tanpa// Output:— perhatikan bahwa fungsi ini tidak muncul pada outputgo test -vdi atas karena hanya dikompilasi, tidak dijalankan.
Aturan Penamaan Contoh #
Nama fungsi menentukan contoh terhubung ke bagian mana dalam dokumentasi:
| Nama contoh | Menunjukkan 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 #
- Blog: Testable Examples in Go — tulisan resmi tentang desain dan manfaat example test.
- Package testing — Examples
— aturan
// Output:,Unordered output:, dan konvensi penamaan.
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 berkaspackage 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 berkaspackage 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())
}