基本測試模式#

func TestDivide(t *testing.T) {
    result, err := Divide(10, 2)

    // 使用 t.Error/t.Errorf 報告錯誤(繼續執行)
    if err != nil {
        t.Errorf("unexpected error: %v", err)
    }
    if result != 5 {
        t.Errorf("Divide(10, 2) = %f; want 5", result)
    }

    // 使用 t.Fatal/t.Fatalf 報告致命錯誤(停止執行)
    _, err = Divide(10, 0)
    if err == nil {
        t.Fatal("expected error for division by zero")
    }
}

表格驅動測試#

這是 Go 社群推薦的測試模式:

func TestAdd(t *testing.T) {
    tests := []struct {
        name     string
        a, b     int
        expected int
    }{
        {"positive numbers", 2, 3, 5},
        {"negative numbers", -2, -3, -5},
        {"mixed numbers", -2, 3, 1},
        {"zeros", 0, 0, 0},
    }

    for _, tt := range tests {
        t.Run(tt.name, func(t *testing.T) {
            result := Add(tt.a, tt.b)
            if result != tt.expected {
                t.Errorf("Add(%d, %d) = %d; want %d",
                    tt.a, tt.b, result, tt.expected)
            }
        })
    }
}

使用 t.Run() 建立子測試的好處:

  1. 每個測試案例獨立執行
  2. 可以個別執行特定案例
  3. 錯誤訊息更清晰

測試輔助函式#

// 使用 t.Helper() 標記輔助函式
func assertEqual(t *testing.T, got, want int) {
    t.Helper()  // 讓錯誤報告指向呼叫者
    if got != want {
        t.Errorf("got %d; want %d", got, want)
    }
}

func TestWithHelper(t *testing.T) {
    result := Add(2, 3)
    assertEqual(t, result, 5)  // 錯誤會報告這一行
}

測試設定與清理#

func TestMain(m *testing.M) {
    // 全域設定(所有測試前執行一次)
    setup()

    code := m.Run()  // 執行所有測試

    // 全域清理(所有測試後執行一次)
    teardown()

    os.Exit(code)
}

func TestWithCleanup(t *testing.T) {
    // 單一測試的清理
    t.Cleanup(func() {
        // 測試結束時執行
        cleanup()
    })

    // 測試邏輯
}
建立臨時測試目錄
func TestFileOperations(t *testing.T) {
    // 建立臨時目錄(測試結束後自動刪除)
    tempDir := t.TempDir()

    // 在臨時目錄中建立測試檔案
    testFile := filepath.Join(tempDir, "test.txt")
    os.WriteFile(testFile, []byte("test content"), 0644)

    // 測試檔案操作
    content, err := os.ReadFile(testFile)
    if err != nil {
        t.Fatal(err)
    }
    if string(content) != "test content" {
        t.Error("content mismatch")
    }
}