Go có testing tích hợp sẵn thông qua package testing và lệnh go test — không cần framework bên ngoài. Test nằm trong các file _test.go, và Go nhấn mạnh mạnh mẽ table-driven test, benchmark, và tooling tốt như các tính năng hạng nhất.
Go có testing tích hợp sẵn thông qua package testing và lệnh go test — không cần framework bên ngoài. Test nằm trong các file _test.go, và Go nhấn mạnh mạnh mẽ table-driven test, benchmark, và tooling tốt như các tính năng hạng nhất.
// math.go
func Add(a, b int) int { return a + b }
// math_test.go — cùng package, hậu tố _test.go
import "testing"
func TestAdd(t *testing.T) { // tiền tố Test + tham số *testing.T
result := Add(2, 3)
if result != 5 {
t.Errorf("Add(2,3) = %d; want 5", result) // báo cáo thất bại (tiếp tục)
// t.Fatalf dừng test ngay lập tức
}
}
// chạy với: go test (hoặc `go test -v` cho verbose, `go test ./...` cho tất cả package)
Một hàm test bắt đầu bằng Test, nhận *testing.T, và báo cáo thất bại qua t.Errorf/t.Fatalf. Không có từ khóa assertion — bạn kiểm tra điều kiện bằng if thông thường và báo cáo thất bại (Go ưa phong cách tường minh này).
func TestAdd(t *testing.T) {
tests := []struct { // một bảng các CASE test
name string
a, b int
expected int
}{
{"positives", 2, 3, 5},
{"with zero", 0, 5, 5},
{"negatives", -1, -1, -2},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { // một SUBTEST cho mỗi case (có tên, cô lập)
if got := Add(tt.a, tt.b); got != tt.expected {
t.Errorf("Add(%d,%d) = %d; want %d", tt.a, tt.b, got, tt.expected)
}
})
}
}
Table-driven test là idiom Go chủ đạo — định nghĩa một slice các case, lặp qua chúng với subtest t.Run. Điều này khiến việc thêm case trở nên dễ dàng và cho báo cáo pass/fail rõ ràng, riêng lẻ cho mỗi case.
func BenchmarkAdd(b *testing.B) {
for i := 0; i < b.N; i++ { // framework chọn b.N để có độ chính xác thống kê
Add(2, 3)
}
}
// go test -bench=. → báo cáo ns/op (và -benchmem cho allocation)
go test -cover # phần trăm coverage
go test -coverprofile=c.out # rồi: go tool cover -html=c.out (báo cáo trực quan)
go test -race # RACE DETECTOR — tìm data race (then chốt cho concurrency)
go test -run TestAdd # chạy test cụ thể
Cờ -race đặc biệt quan trọng — nó phát hiện data race trong code concurrent, một công cụ then chốt do sự tập trung vào concurrency của Go.
func TestMain(m *testing.M) { // setup/teardown ở cấp package
setup()
code := m.Run()
teardown()
os.Exit(code)
}
// t.Helper() đánh dấu một hàm là test helper (báo cáo dòng thất bại tốt hơn)
// package httptest để test các HTTP handler; interface để mock các phụ thuộc
Testing là một phần tích hợp sẵn, hạng nhất của Go — package testing và go test không cần framework bên ngoài, phản ánh sự nhấn mạnh của Go đối với testing như một thực hành cốt lõi.
Hiểu các quy ước là kiến thức hàng ngày thiết yếu: cấu trúc file _test.go và TestXxx(t *testing.T), phong cách báo-cáo-thất-bại tường minh (không assertion), và đặc biệt là pattern table-driven test chủ đạo trong Go idiomatic (bao quát gọn gàng nhiều case với báo cáo theo từng case rõ ràng qua subtest).
Quan trọng không kém là benchmark tích hợp sẵn của Go (hiệu năng như một mối quan tâm có thể test được) và tooling mạnh mẽ — phân tích coverage và đặc biệt là race detector -race, vốn tìm data race trong code concurrent (quan trọng do Go được dùng nhiều cho concurrency).
Biết cách viết các test Go idiomatic hiệu quả, dùng race detector, và tận dụng httptest/interface để test các thành phần thực là dấu hiệu của phát triển Go chuyên nghiệp và là một chủ đề thường gặp phản ánh sự thông thạo về chất lượng code.
Thư viện câu hỏi phỏng vấn IT với đáp án chi tiết — từ Junior đến Senior.
Ủng hộ