ข้ามไปยังเนื้อหา

Testing & Tooling

ภาษาส่วนใหญ่ต้องการ testing framework จาก third-party แต่ Go มีทุกอย่างที่จำเป็นอยู่ใน standard library แล้ว package testing มี *testing.T สำหรับ unit tests, *testing.B สำหรับ benchmarks, และ *testing.F สำหรับ fuzzing — ทั้งหมดขับเคลื่อนด้วยคำสั่งเดียว: go test

go toolchain ที่ติดตั้งมาพร้อมกับ Go ทุกเวอร์ชันยังรวมถึง:

เครื่องมือวัตถุประสงค์
go testรัน tests และ benchmarks
go buildcompile packages และ binary
go runcompile และรันในขั้นตอนเดียว
go fmtจัดรูปแบบ source code (เรียกใช้ gofmt)
go vetstatic analysis สำหรับข้อผิดพลาดทั่วไป
go modจัดการ module และ dependency
go docเรียกดู package documentation
  1. go-test — การเขียนไฟล์ _test.go, func TestXxx(t *testing.T), และ table-driven tests ด้วย t.Run
  2. benchmarks — การวัด performance ด้วย func BenchmarkXxx(b *testing.B) และการอ่านผลลัพธ์จาก -benchmem
  3. modules — การจัดการ dependency ด้วย go mod init, go.mod, go.sum, และ go get
  4. go-tooling — คำสั่งประจำวัน: go run, go build, go fmt, go vet, และ go doc

วิธีที่ดีที่สุดในการทำความเข้าใจ testing tools ของ Go คือเริ่มต้นด้วย pure function — ฟังก์ชันที่ไม่มี side effect ไม่มี I/O มีแค่ input และ output Playground ด้านล่างรัน Fibonacci และ IsPrime จาก main ในบทเรียนถัดไปคุณจะเขียนไฟล์ _test.go สำหรับฟังก์ชันแบบนี้โดยตรง

package main
import "fmt"
// Fibonacci returns the nth Fibonacci number (0-indexed).
// fib(0)=0, fib(1)=1, fib(2)=1, fib(3)=2, ...
func Fibonacci(n int) int {
if n <= 1 {
return n
}
return Fibonacci(n-1) + Fibonacci(n-2)
}
// IsPrime reports whether n is a prime number.
func IsPrime(n int) bool {
if n < 2 {
return false
}
for i := 2; i*i <= n; i++ {
if n%i == 0 {
return false
}
}
return true
}
func main() {
// Print the first 10 Fibonacci numbers
fmt.Println("Fibonacci sequence:")
for i := 0; i < 10; i++ {
fmt.Printf(" fib(%d) = %d\n", i, Fibonacci(i))
}
// Find primes up to 30
fmt.Println("Primes up to 30:")
for n := 2; n <= 30; n++ {
if IsPrime(n) {
fmt.Printf(" %d\n", n)
}
}
}
ApproachBenefitCost
built-in testing packageไม่ต้อง install, standard API ทุก Go projectไม่มี assertion library — ต้องเขียน if got != want เอง
table-driven teststest หลาย case ใน 1 function, เพิ่ม case ได้ง่ายถ้า table ยาวมาก อ่านยาก
go test ./...รัน test ทุก package ใน module ครั้งเดียวparallel test อาจ race ถ้าไม่ระวัง shared state
race detector (-race)ตรวจหา concurrent bugs อัตโนมัติช้าลง 2-10x — ควรรันใน CI ไม่ใช่ทุก local run
  • ต้องใช้ testing framework เหมือน Python/Node — Go standard library มีทุกอย่างที่ต้องการ ไม่ต้องติดตั้ง testify หรือ gomega เพิ่ม
  • coverage 100% = code ปลอดภัย — coverage วัดว่า line ถูกรันหรือไม่ ไม่ได้วัด correctness — test ที่ไม่มี assertion ก็ทำให้ coverage 100% ได้
  • go test ช้าgo test cache ผลลัพธ์ — ถ้าไม่มีไฟล์เปลี่ยน จะ return cached result ทันที

💡 ตัวอย่างจากของจริง

Kubernetes ใช้ go test ./... ทั้งหมด ไม่ใช้ external testing framework — standard library เพียงพอสำหรับ codebase ระดับ enterprise

Docker enforce -race flag ใน CI pipeline ทุก PR เพื่อตรวจจับ concurrent bug ก่อน merge

คำสั่งใดรัน tests ทั้งหมดใน module ปัจจุบันและทุก sub-package?
package ใดใน Go standard library ที่ให้ *testing.T และ *testing.B?
อะไรทำให้ฟังก์ชันเป็น candidate ที่ดีสำหรับ unit test แรก?
เครื่องมือใดจัดรูปแบบ Go source code ตาม canonical style?