table test, fuzz, synctest, JSON v2, HTTP
เขียนเคสเป็นตาราง คุ้มสุด:
func TestAdd(t *testing.T) {
tests := []struct{ a, b, want int }{{1,2,3},{0,0,0},{-1,1,0}}
for _, tt := range tests {
if got := Add(tt.a, tt.b); got != tt.want {
t.Errorf("Add(%d,%d)=%d want %d", tt.a, tt.b, got, tt.want)
}
}
}func FuzzParse(f *testing.F) {
f.Add("1-2")
f.Fuzz(func(t *testing.T, s string) { _, _ = Parse(s) }) // โยนขยะแล้วต้องไม่ panic
}go test -fuzz=FuzzParse -fuzztime=30s
go test -bench=. -benchmem
go tool pprof -http=:8080 cpu.out # 1.26 เปิดมาเป็น flame graph เลยGo 1.27 มี 2 ของคู่กัน:
httptest.NewTestServer = เซิร์ฟเวอร์ปลอมใน memory ไม่กินพอร์ตจริงtesting/synctest = ห้องจำลองเวลาสำหรับเทสต์ concurrent ไม่ต้อง sleep จริง ลด flakysrv := httptest.NewTestServer(myHandler)
defer srv.Close()
resp, _ := http.Get(srv.URL)
synctest.Test(t, func(t *testing.T) {
// รันโค้ด channel/time ในโลกจำลอง
})ข่าวดี: Go 1.27 เอาไส้ json/v2 มาใส่ใน encoding/json เดิมแล้ว = โค้ดเดิมเร็วขึ้นโดยไม่แก้:
type User struct {
Name string `json:"name"`
Age int `json:"age"`
}
b, _ := json.Marshal(User{"Ann", 20})อยากซิ่ง/เข้มค่อยใช้:
encoding/json/v2 = ตั้งค่าได้ (deterministic, unknown fields)encoding/json/jsontext = สตรีมทีละ token เหมาะไฟล์ยักษ์ทุก handler รับ ctx มาด้วยเพื่อ timeout/yกเลิก:
func userHandler(w http.ResponseWriter, r *http.Request) {
ctx, cancel := context.WithTimeout(r.Context(), 2*time.Second)
defer cancel()
// ... ใช้ ctx กับ DB / เรียกต่อ ...
json.NewEncoder(w).Encode(user)
}Mini: ทำ API /price?symbol=AAPL ดึงราคาปลอม (sleep สุ่ม) + timeout 500ms + table test + NewTestServer test + go test -race ต้องผ่าน
func TestAdd(t *testing.T) {
tests := []struct {
name string
a, b int
want int
}{
{"บวกปกติ", 1, 2, 3},
{"ติดลบ", -1, -2, -3},
{"ศูนย์", 0, 0, 0},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := Add(tt.a, tt.b); got != tt.want {
t.Errorf("Add(%d,%d) = %d อยากได้ %d", tt.a, tt.b, got, tt.want)
}
})
}
}func FuzzReverse(f *testing.F) {
f.Add("hello")
f.Add("")
f.Fuzz(func(t *testing.T, s string) {
if got := Reverse(Reverse(s)); got != s {
t.Errorf("กลับไปกลับมาไม่ได้: %q", s)
}
})
}srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("ok"))
}))
defer srv.Close()
res, err := http.Get(srv.URL)
if err != nil || res.StatusCode != 200 {
t.Fatal("server ไม่ตอบ")
}t.Run("ติดลบ", ...)) fail แล้วรู้เลยเคสไหน-race ทุกครั้งก่อน pushhttptest ไม่ต้องเปิด port จริงstatusOf (จากเล่ม errors) ครบ 3 เคสReverse 1 นาทีแล้วแก้บั๊กที่เจออ้างอิง: Go 1.27 blog (json/v2, NewTestServer, synctest), Go 1.26 blog (Green Tea GC, pprof flame default)