昨天我們建立了最小的 REST API /healthz
,伺服器可以正常回應 "ok"
。
今天要為專案補上 測試骨架,讓我們在之後開發新功能時,不用害怕改壞現有程式。
Go 本身就內建測試框架,不需要額外安裝。這是 Go 語言的一大特色:測試是一等公民。
在 Go 社群裡,最常見的測試模式是 table-driven test。
它的想法很簡單:把「輸入」和「預期輸出」放在一張表格(slice),然後用迴圈跑一遍。
這麼做有三個好處:
Go 的慣例:
_test.go
結尾。TestXxx(t *testing.T)
命名。在專案根目錄新增 main_test.go
:
package main
import (
"net/http"
"net/http/httptest"
"testing"
)
func TestHealthHandler(t *testing.T) {
tests := []struct {
name string
url string
wantStatus int
wantBody string
}{
{
name: "healthz should return ok",
url: "/healthz",
wantStatus: http.StatusOK,
wantBody: "ok\n",
},
{
name: "unknown path should return 404",
url: "/notfound",
wantStatus: http.StatusNotFound,
wantBody: "404 page not found\n",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
req := httptest.NewRequest(http.MethodGet, tt.url, nil)
w := httptest.NewRecorder()
// 使用我們的 handler 註冊路由
mux := http.NewServeMux()
mux.HandleFunc("/healthz", healthHandler)
mux.ServeHTTP(w, req)
if w.Code != tt.wantStatus {
t.Errorf("got status %d, want %d", w.Code, tt.wantStatus)
}
if w.Body.String() != tt.wantBody {
t.Errorf("got body %q, want %q", w.Body.String(), tt.wantBody)
}
})
}
}
在專案目錄下執行:
go test ./...
預期輸出:
ok github.com/<yourname>/cloud-native-search 0.002s
如果要看更詳細的測試名稱,可以加 -v
:
go test -v
今天我們完成了:
httptest
建立假請求/healthz
正確回傳 "ok"
這個測試骨架能確保我們未來加功能時,API 行為仍然正確。
👉 明天(Day 4),我們會開始處理 中介層 (middleware),加入結構化日誌與設定管理,讓服務邁向更專業的實戰環境。