Cara Membuat Unit Test Pada Golang
Unit Testing Menggunakan Library Go
Pemrograman tidak mudah bahkan programmer terbaik tidak mampu menulis program yang bekerja persis seperti yang diinginkan setiap saat. Oleh karena itu bagian penting dari proses pengembangan perangkat lunak adalah pengujian (testing). Menulis test untuk kode kita adalah cara yang baik untuk memastikan kualitas dan meningkatkan keandalan.
Go menyediakan package testing, berisikan banyak sekali tools untuk keperluan unit test. Pada chapter ini kita akan belajar mengenai testing, benchmark, dan juga testing menggunakan testify.
Go menyertakan program khusus yang membuat tes menulis lebih mudah, jadi mari kita buat beberapa test untuk paket yang kita buat di sesi ini. Di folder 01-math buat file baru bernama math_test.go yang berisi ini.
Sebelumnya kita telah buat suatu function sebagai berikut ini.
1package main
2
3func Average(xs []float64) float64 {
4 total := float64(0)
5 for _, x := range xs {
6 total += x
7 }
8 return total / float64(len(xs))
9}vscode, maka akan membuat file baru math_test.go dan men-generate fungsi TestAverage dengan isi dibawah ini. 1func TestAverageGenerate(t *testing.T) {
2 type args struct {
3 xs []float64
4 }
5 tests := []struct {
6 name string
7 args args
8 want float64
9 }{
10 {
11 name: "must 10",
12 args: args{
13 xs: []float64{10.0, 10.0},
14 },
15 want: float64(10),
16 },
17 }
18 for _, tt := range tests {
19 t.Run(tt.name, func(t *testing.T) {
20 if got := Average(tt.args.xs); got != tt.want {
21 t.Errorf("Average() = %v, want %v", got, tt.want)
22 }
23 })
24 }
25}Unit Test Program Ganjil Genap
Buat fungsi untuk menentukan bahwa program tersebut mengeluarkan informasi yang diinput terkait angka ganjil dan genap.
1func GanjilGenap(angka int) string {
2 if angka%2 == 0 {
3 return "genap"
4 }
5 return "ganjil"
6} 1package math
2
3import (
4 "testing"
5)
6
7func TestAverageGenerate(t *testing.T) {
8 type args struct {
9 xs []float64
10 }
11 tests := []struct {
12 name string
13 args args
14 want float64
15 }{
16 {
17 name: "must 10",
18 args: args{
19 xs: []float64{10.0, 10.0},
20 },
21 want: float64(10),
22 },
23 }
24 for _, tt := range tests {
25 t.Run(tt.name, func(t *testing.T) {
26 if got := Average(tt.args.xs); got != tt.want {
27 t.Errorf("Average() = %v, want %v", got, tt.want)
28 }
29 })
30 }
31}
32
33type testpair struct {
34 values []float64
35 average float64
36}
37
38var tests = []testpair{
39 {[]float64{1, 2}, 1.5},
40 {[]float64{1, 1, 1, 1, 1, 1}, 1},
41 {[]float64{-1, 1}, 0},
42}
43
44func TestAverage(t *testing.T) {
45 for _, pair := range tests {
46 v := Average(pair.values)
47 if v != pair.average {
48 }
49 }
50}
51
52func TestGanjilGenap(t *testing.T) {
53 type args struct {
54 angka int
55 }
56 tests := []struct {
57 name string
58 args args
59 want string
60 }{
61 {
62 name: "test case mengeluarkan ganjil",
63 args: args{
64 angka: 1,
65 },
66 want: "ganjil",
67 },
68 {
69 name: "test case mengeluarkan genap",
70 args: args{
71 angka: 2,
72 },
73 want: "genap",
74 },
75 {
76 name: "test case mengeluarkan -1",
77 args: args{
78 angka: -1,
79 },
80 want: "ganjil",
81 },
82 }
83 for _, tt := range tests {
84 t.Run(tt.name, func(t *testing.T) {
85 if got := GanjilGenap(tt.args.angka); got != tt.want {
86 t.Errorf("GanjilGenap() = %v, want %v", got, tt.want)
87 }
88 })
89 }
90}Testing Tabung
Pertama siapkan terlebih dahulu sebuah struct Tabung. Variabel object hasil struct ini nantinya kita gunakan sebagai bahan testing.
1package math
2
3import "math"
4
5type Tabung struct {
6 Jarijari, Tinggi float64
7}
8
9func (t Tabung) Volume() float64 {
10 return math.Phi * math.Pow(t.Jarijari, 2) * t.Tinggi
11}
12
13func (t Tabung) Luas() float64 {
14 return 2 * math.Phi * t.Jarijari * (t.Jarijari + t.Tinggi)
15}
16
17func (t Tabung) KelilingAlas() float64 {
18 return 2 * math.Phi * t.Jarijari
19}Unit Test untuk fungsi Volume
1func TestTabung_Volume(t *testing.T) {
2 type fields struct {
3 Jarijari float64
4 Tinggi float64
5 }
6 tests := []struct {
7 name string
8 fields fields
9 want float64
10 }{
11 {
12 name: "testing hitung volume",
13 fields: fields{
14 Jarijari: 7, Tinggi: 10,
15 },
16 want: float64(792.8366544874485),
17 },
18 }
19 for _, tt := range tests {
20 t.Run(tt.name, func(t *testing.T) {
21 tr := Tabung{
22 Jarijari: tt.fields.Jarijari,
23 Tinggi: tt.fields.Tinggi,
24 }
25 if got := tr.Volume(); got != tt.want {
26 t.Errorf("Tabung.Volume() = %v, want %v", got, tt.want)
27 }
28 })
29 }
30}Unit Test untuk fungsi Luas Permukaan
1func TestTabung_Luas(t *testing.T) {
2 type fields struct {
3 Jarijari float64
4 Tinggi float64
5 }
6 tests := []struct {
7 name string
8 fields fields
9 want float64
10 }{
11 {
12 name: "testing hitung luas permukaan",
13 fields: fields{
14 Jarijari: 7, Tinggi: 10,
15 },
16 want: float64(385.092089322475),
17 },
18 }
19 for _, tt := range tests {
20 t.Run(tt.name, func(t *testing.T) {
21 tr := Tabung{
22 Jarijari: tt.fields.Jarijari,
23 Tinggi: tt.fields.Tinggi,
24 }
25 if got := tr.Luas(); got != tt.want {
26 t.Errorf("Tabung.Luas() = %v, want %v", got, tt.want)
27 }
28 })
29 }
30}Unit test untuk Keliling Alas
1func TestTabung_KelilingAlas(t *testing.T) {
2 type fields struct {
3 Jarijari float64
4 Tinggi float64
5 }
6 tests := []struct {
7 name string
8 fields fields
9 want float64
10 }{
11 {
12 name: "testing hitung keliling alas",
13 fields: fields{
14 Jarijari: 7, Tinggi: 10,
15 },
16 want: float64(22.65247584249853),
17 },
18 }
19 for _, tt := range tests {
20 t.Run(tt.name, func(t *testing.T) {
21 tr := Tabung{
22 Jarijari: tt.fields.Jarijari,
23 Tinggi: tt.fields.Tinggi,
24 }
25 if got := tr.KelilingAlas(); got != tt.want {
26 t.Errorf("Tabung.KelilingAlas() = %v, want %v", got, tt.want)
27 }
28 })
29 }
30}go test. Argument -v atau verbose digunakan menampilkan semua output log pada saat pengujian.Jalankan program seperti di bawah ini, terlihat bahwa tidak ada test yang fail.
1➜ tabung git:(main) ✗ go test -v
2=== RUN TestTabung_Volume
3=== RUN TestTabung_Volume/testing_hitung_volume
4--- PASS: TestTabung_Volume (0.00s)
5 --- PASS: TestTabung_Volume/testing_hitung_volume (0.00s)
6=== RUN TestTabung_Luas
7=== RUN TestTabung_Luas/testing_hitung_luas_permukaan
8--- PASS: TestTabung_Luas (0.00s)
9 --- PASS: TestTabung_Luas/testing_hitung_luas_permukaan (0.00s)
10=== RUN TestTabung_KelilingAlas
11=== RUN TestTabung_KelilingAlas/testing_hitung_keliling_alas
12--- PASS: TestTabung_KelilingAlas (0.00s)
13 --- PASS: TestTabung_KelilingAlas/testing_hitung_keliling_alas (0.00s)
14PASS
15ok github.com/santekno/tabung 0.486sMethod Test
| Method | Kegunaan |
|---|---|
Log() | Menampilkan log |
Logf() | Menampilkan log menggunakan format |
Fail() | Menandakan terjadi Fail() dan proses testing fungsi tetap diteruskan |
FailNow() | Menandakan terjadi Fail() dan proses testing fungsi dihentikan |
Failed() | Menampilkan laporan fail |
Error() | Log() diikuti dengan Fail() |
Errorf() | Logf() diikuti dengan Fail() |
Fatal() | Log() diikuti dengan failNow() |
Fatalf() | Logf() diikuti dengan failNow() |
Skip() | Log() diikuti dengan SkipNow() |
Skipf() | Logf() diikuti dengan SkipNow() |
SkipNow() | Menghentikan proses testing fungsi, dilanjutkan ke testing fungsi |
Skiped() | Menampilkan laporan skip |
Parallel() | Menge-set bahwa eksekusi testing adalah parallel |
Catatan Perintah Test
Perintah untuk melihat coverage dari unit test dalam projek
1➜ tabung git:(main) ✗ go test -coverprofile=coverage.out
2PASS
3coverage: 100.0% of statements
4ok github.com/santekno/tabung 0.750sPerintah untuk melihat code mana saja yang sudah cover unit test
1➜ tabung git:(main) ✗ go tool cover -html=coverage.outgenerate html yang berupa visualiasi dari unit test yg sudah tercover ataupun yang belumPerintah untuk melakukan generate ulang menggunakan moq
1$ cd <folder-yang-akan-di-generate>
2$ go generate ./...struct seperti ini1// go:generate moq -out main_mock_test.go . UserRepositoryInterfacego:generate moq -out <nama-file-mock-test> . <struct-interface-yang-akan-dibuat-mock>