Go Testing di 2026: Unit Test, Mock, dan Pertanyaan Wawancara Teknis
Kuasai testing Go dengan table-driven test, mock, dan pola yang diharapkan pewawancara. Contoh praktis dengan testify dan gomock.

Testing di Go bergantung pada package standar testing, yang tersedia di setiap instalasi Go tanpa memerlukan dependensi eksternal. Berbeda dengan framework di bahasa lain, pendekatan Go mengutamakan kesederhanaan: file test berada di direktori yang sama dengan kode produksi, fungsi test mengikuti konvensi penamaan, dan perintah go test menangani penemuan dan eksekusi secara otomatis.
Kandidat yang menulis table-driven test, menggunakan interface untuk dependency injection, dan memahami kapan mocking memberikan nilai versus kapan hanya menambah kompleksitas.
Menulis Unit Test dengan Package testing
Setiap file test diakhiri dengan _test.go dan berada di package yang sama dengan kode yang diuji. Fungsi test dimulai dengan Test diikuti nama dengan huruf kapital. Parameter *testing.T menyediakan method untuk melaporkan kegagalan.
package calculator
import "testing"
func TestAdd(t *testing.T) {
result := Add(2, 3)
if result != 5 {
t.Errorf("Add(2, 3) = %d; want 5", result)
}
}Menjalankan go test ./... mengeksekusi semua test di modul saat ini. Flag -v menampilkan nama test individual dan status berhasil/gagal.
Table-Driven Test: Standar Go
Table-driven test mengurangi duplikasi dan membuat penambahan kasus baru menjadi trivial. Setiap baris di tabel merepresentasikan satu skenario dengan input dan output yang diharapkan. Pola ini muncul di library standar Go dan di codebase produksi di seluruh industri.
package validator
import "testing"
func TestValidateEmail(t *testing.T) {
tests := []struct {
name string
email string
wantErr bool
}{
{"valid email", "user@example.com", false},
{"missing at sign", "userexample.com", true},
{"empty string", "", true},
{"unicode local part", "user@例え.jp", false},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := ValidateEmail(tt.email)
if (err != nil) != tt.wantErr {
t.Errorf("ValidateEmail(%q) error = %v, wantErr %v",
tt.email, err, tt.wantErr)
}
})
}
}Method t.Run membuat subtest yang berjalan secara independen. Subtest yang gagal melaporkan kasus spesifik mana yang gagal tanpa menghentikan kasus lainnya.
Dependency Injection Melalui Interface
Interface Go memungkinkan pengujian kode yang bergantung pada sistem eksternal: database, HTTP client, file system. Mendefinisikan interface minimal di titik penggunaan memungkinkan penggantian implementasi nyata dengan test double.
package order
// Repository defines the data access methods this service needs
type Repository interface {
FindByID(id string) (*Order, error)
Save(order *Order) error
}
// Service handles order business logic
type Service struct {
repo Repository
}
// NewService creates a service with the given repository
func NewService(repo Repository) *Service {
return &Service{repo: repo}
}
// Process validates and saves an order
func (s *Service) Process(order *Order) error {
if order.Total <= 0 {
return ErrInvalidTotal
}
return s.repo.Save(order)
}Service menerima tipe apapun yang memenuhi Repository. Kode produksi meneruskan implementasi berbasis database. Test meneruskan mock atau stub.
Mocking dengan gomock dan mockgen
Package gomock menghasilkan implementasi mock dari definisi interface. Perintah mockgen membaca file sumber dan menghasilkan struct mock yang merekam pemanggilan dan mengembalikan nilai yang dikonfigurasi.
# Generate mocks for the Repository interface
mockgen -source=service.go -destination=mocks/repository_mock.go -package=mocksMenggunakan mock yang dihasilkan dalam test:
package order
import (
"testing"
"github.com/stretchr/testify/assert"
"go.uber.org/mock/gomock"
"yourmodule/order/mocks"
)
func TestService_Process_SavesValidOrder(t *testing.T) {
ctrl := gomock.NewController(t)
mockRepo := mocks.NewMockRepository(ctrl)
order := &Order{ID: "123", Total: 99.99}
// Expect Save to be called once with this order, return nil
mockRepo.EXPECT().
Save(order).
Return(nil).
Times(1)
svc := NewService(mockRepo)
err := svc.Process(order)
assert.NoError(t, err)
}
func TestService_Process_RejectsZeroTotal(t *testing.T) {
ctrl := gomock.NewController(t)
mockRepo := mocks.NewMockRepository(ctrl)
// No calls expected to repo since validation fails first
svc := NewService(mockRepo)
err := svc.Process(&Order{ID: "456", Total: 0})
assert.ErrorIs(t, err, ErrInvalidTotal)
}Mock memverifikasi bahwa Save dipanggil tepat satu kali dengan argumen yang diharapkan. Jika kode yang diuji tidak pernah memanggil Save, atau memanggilnya dengan argumen berbeda, test gagal.
Menggunakan testify untuk Assertion dan Suite
testify menyediakan fungsi assertion yang menghasilkan pesan kegagalan lebih jelas dibanding pengecekan if manual. Package assert melanjutkan eksekusi setelah kegagalan. Package require menghentikan test segera.
package user
import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestParseUser(t *testing.T) {
input := `{"id": "u1", "name": "Alice"}`
user, err := ParseUser(input)
require.NoError(t, err, "parsing should not fail")
assert.Equal(t, "u1", user.ID)
assert.Equal(t, "Alice", user.Name)
assert.Empty(t, user.Email, "email should default to empty")
}Panggilan require.NoError menghentikan test jika parsing gagal, mencegah panic nil pointer pada assertion berikutnya.
Siap menguasai wawancara Go Anda?
Berlatih dengan simulator interaktif, flashcards, dan tes teknis kami.
Testing HTTP Handler dengan httptest
Package net/http/httptest menyediakan ResponseRecorder untuk menangkap output handler dan Server untuk menjalankan server test lokal. Sebagian besar unit test menggunakan ResponseRecorder untuk menghindari overhead jaringan.
package api
import (
"net/http"
"net/http/httptest"
"testing"
"github.com/stretchr/testify/assert"
)
func TestHealthHandler(t *testing.T) {
req := httptest.NewRequest(http.MethodGet, "/health", nil)
rec := httptest.NewRecorder()
HealthHandler(rec, req)
assert.Equal(t, http.StatusOK, rec.Code)
assert.JSONEq(t, `{"status": "ok"}`, rec.Body.String())
}Untuk handler yang memanggil layanan eksternal, inject mock client atau gunakan httptest.NewServer untuk membuat backend palsu.
Pertanyaan Wawancara Umum tentang Go Testing
Pewawancara menilai pengetahuan testing melalui pertanyaan yang mengungkap pengalaman dengan codebase nyata. Berikut pola yang membedakan kandidat yang siap:
"Bagaimana Anda menguji fungsi yang memanggil API eksternal?"
Definisikan interface untuk HTTP client, inject ke dalam fungsi atau struct, dan sediakan mock yang mengembalikan respons yang telah ditentukan. Ini menghindari panggilan jaringan dan membuat test deterministik.
"Kapan menggunakan stub versus mock?"
Stub mengembalikan respons yang telah ditentukan tanpa memverifikasi bagaimana mereka dipanggil. Mock memverifikasi bahwa method tertentu dipanggil dengan argumen tertentu. Gunakan stub ketika nilai kembalian lebih penting daripada interaksi. Gunakan mock ketika memverifikasi interaksi adalah tujuan test.
"Apa itu table-driven test dan mengapa Go menyukainya?"
Table-driven test mendefinisikan kasus test sebagai data dalam slice of struct. Mereka mengurangi boilerplate, membuat penambahan kasus menjadi trivial, dan menghasilkan output test yang mudah dibaca dengan t.Run. Pola ini selaras dengan preferensi Go untuk kode eksplisit dan repetitif daripada abstraksi yang rumit.
"Bagaimana menangani fixture test atau setup yang digunakan bersama oleh beberapa test?"
Gunakan TestMain untuk setup dan teardown level package. Gunakan fungsi helper atau test suite (dari testify) untuk setup bersama antar test terkait. Hindari state global yang menciptakan coupling antar test.
Mempersiapkan wawancara Go? Modul testing Go membahas pola-pola ini secara mendalam dengan pertanyaan latihan.
Menjalankan Test dengan Coverage dan Race Detection
Perintah go test menerima flag yang mengungkap jalur kode yang belum diuji dan bug concurrency.
# Run tests with coverage report
go test -cover ./...
# Generate HTML coverage visualization
go test -coverprofile=coverage.out ./...
go tool cover -html=coverage.out -o coverage.html
# Detect race conditions (slower, but catches real bugs)
go test -race ./...Race detector menginstrumentasi akses memori dan menandai pembacaan dan penulisan bersamaan ke variabel yang sama. Menjalankan test dengan -race di CI menangkap bug yang hanya muncul pada timing tertentu.
Mengorganisir Test di Codebase Besar
Seiring pertumbuhan proyek, organisasi test mempengaruhi maintainability:
- Same package test (
package foo) mengakses fungsi dan field yang tidak diekspor. Gunakan untuk unit test yang memverifikasi perilaku internal. - External package test (
package foo_test) mengimpor package seperti kode eksternal. Gunakan untuk integration test dan memverifikasi public API. - Direktori testdata menyimpan fixture seperti file JSON, golden output, atau seed database. Go mengabaikan ini saat build.
- Build tag memisahkan unit test dari integration test yang memerlukan sistem eksternal. Jalankan
go test -tags=integration ./...untuk menyertakannya.
Untuk lebih lanjut tentang best practice Go di luar testing, artikel pola concurrency membahas goroutine dan channel.
Hal yang Perlu Diingat tentang Go Testing
- Package
testingtersedia bersama Go dan tidak memerlukan dependensi eksternal - Table-driven test mengurangi duplikasi dan merupakan pola yang diharapkan dalam wawancara
- Interface memungkinkan dependency injection; definisikan di titik penggunaan, bukan di implementasi
gomockmenghasilkan mock dari interface;testifymenyediakan assertion yang lebih bersihhttptest.ResponseRecordermenangkap output handler tanpa overhead jaringan- Flag
-racemendeteksi bug concurrency yang tidak tertangkap unit test biasa - Metrik coverage memandu perhatian tetapi tidak menjamin kebenaran
Mulai berlatih!
Uji pengetahuan Anda dengan simulator wawancara dan tes teknis kami.
Bisakah kamu menemukan bug di Go?
Satu potongan kode nyata, satu bug tersembunyi, satu percobaan per hari. Tanpa akun untuk mencoba.

Ditulis oleh
Anthony Fillion-MailletPendiri SharpSkill
Developer fullstack selama lebih dari 10 tahun. Ia menjalankan SharpSkill dan bertanggung jawab atas semua yang diterbitkan di sini.
Diperbarui 24 Agustus 2026
Bagikan
Artikel terkait

Profiling dan Benchmarking Go 2026: pprof, trace, dan Pertanyaan Interview
Panduan lengkap profiling Go dengan pprof dan runtime/trace. Teknik analisis CPU, memori, dan goroutine untuk optimasi performa serta persiapan interview.

Interface Go Tingkat Lanjut di 2026: Komposisi, Type Assertion, dan Pertanyaan Interview
Panduan mendalam tentang interface Go modern: komposisi interface, type assertion yang aman, generic self-referential, dan pertanyaan interview yang sering muncul untuk developer Go.

Go Context Package 2026: Pembatalan, Timeout, dan Pertanyaan Wawancara
Kuasai package context Go untuk pembatalan, timeout, dan request-scoped values. Panduan lengkap dengan contoh kode dan pertanyaan wawancara.