/* 04-testing.go - Go 语言测试详解 学习目标: 1. 理解 Go 语言测试的基本概念 2. 掌握单元测试的编写方法 3. 学会基准测试和性能分析 4. 了解测试覆盖率和测试工具 5. 掌握测试的最佳实践 知识点: - 测试函数的命名和签名 - testing 包的使用 - 表驱动测试模式 - 基准测试和内存分析 - 测试覆盖率 - 测试工具和技巧 */ package main import ( "fmt" "sort" "strings" "time" ) // 这个文件演示了如何编写各种类型的测试 // 注意:实际的测试文件应该以 _test.go 结尾 func main() { fmt.Println("=== Go 语言测试详解 ===\n") // 演示测试的基本概念 demonstrateTestingBasics() // 演示单元测试 demonstrateUnitTesting() // 演示表驱动测试 demonstrateTableDrivenTests() // 演示基准测试 demonstrateBenchmarkTesting() // 演示示例测试 demonstrateExampleTesting() // 演示测试工具和技巧 demonstrateTestingTools() // 演示测试的最佳实践 demonstrateTestingBestPractices() } // demonstrateTestingBasics 演示测试的基本概念 func demonstrateTestingBasics() { fmt.Println("1. 测试的基本概念:") // 测试的重要性 fmt.Printf(" 测试的重要性:\n") fmt.Printf(" - 验证代码的正确性\n") fmt.Printf(" - 防止回归错误\n") fmt.Printf(" - 提高代码质量\n") fmt.Printf(" - 便于重构和维护\n") fmt.Printf(" - 作为代码的文档\n") // Go 测试的特点 fmt.Printf(" Go 测试的特点:\n") fmt.Printf(" - 内置测试框架\n") fmt.Printf(" - 简单的测试语法\n") fmt.Printf(" - 强大的工具支持\n") fmt.Printf(" - 并行测试支持\n") fmt.Printf(" - 基准测试集成\n") // 测试文件的组织 fmt.Printf(" 测试文件的组织:\n") fmt.Printf(" 源文件: calculator.go\n") fmt.Printf(" 测试文件: calculator_test.go\n") fmt.Printf(" \n") fmt.Printf(" 源文件: utils.go\n") fmt.Printf(" 测试文件: utils_test.go\n") // 测试函数的类型 fmt.Printf(" 测试函数的类型:\n") fmt.Printf(" 1. 单元测试: func TestXxx(*testing.T)\n") fmt.Printf(" 2. 基准测试: func BenchmarkXxx(*testing.B)\n") fmt.Printf(" 3. 示例测试: func ExampleXxx()\n") fmt.Printf(" 4. 模糊测试: func FuzzXxx(*testing.F) (Go 1.18+)\n") // 运行测试的命令 fmt.Printf(" 运行测试的命令:\n") fmt.Printf(" go test # 运行当前包的测试\n") fmt.Printf(" go test ./... # 运行所有子包的测试\n") fmt.Printf(" go test -v # 详细输出\n") fmt.Printf(" go test -run TestAdd # 运行特定测试\n") fmt.Printf(" go test -bench=. # 运行基准测试\n") fmt.Printf(" go test -cover # 显示覆盖率\n") fmt.Println() } // demonstrateUnitTesting 演示单元测试 func demonstrateUnitTesting() { fmt.Println("2. 单元测试:") // 基本测试函数 fmt.Printf(" 基本测试函数:\n") fmt.Printf(" func TestAdd(t *testing.T) {\n") fmt.Printf(" result := Add(2, 3)\n") fmt.Printf(" expected := 5\n") fmt.Printf(" if result != expected {\n") fmt.Printf(" t.Errorf(\\\"Add(2, 3) = %%d; want %%d\\\", result, expected)\n") fmt.Printf(" }\n") fmt.Printf(" }\n") // 模拟运行测试 fmt.Printf(" 模拟运行测试:\n") mockT := &MockT{} // 测试 Add 函数 fmt.Printf(" 测试 Add 函数:\n") TestAdd(mockT) if mockT.failed { fmt.Printf(" ❌ 测试失败: %s\n", mockT.errorMsg) } else { fmt.Printf(" ✅ 测试通过\n") } // 测试 Divide 函数 fmt.Printf(" 测试 Divide 函数:\n") mockT = &MockT{} TestDivide(mockT) if mockT.failed { fmt.Printf(" ❌ 测试失败: %s\n", mockT.errorMsg) } else { fmt.Printf(" ✅ 测试通过\n") } // 测试 IsPrime 函数 fmt.Printf(" 测试 IsPrime 函数:\n") mockT = &MockT{} TestIsPrime(mockT) if mockT.failed { fmt.Printf(" ❌ 测试失败: %s\n", mockT.errorMsg) } else { fmt.Printf(" ✅ 测试通过\n") } // testing.T 的方法 fmt.Printf(" testing.T 的方法:\n") fmt.Printf(" t.Error(args ...) # 记录错误但继续测试\n") fmt.Printf(" t.Errorf(format, args ...) # 格式化错误信息\n") fmt.Printf(" t.Fatal(args ...) # 记录错误并停止测试\n") fmt.Printf(" t.Fatalf(format, args ...) # 格式化致命错误\n") fmt.Printf(" t.Log(args ...) # 记录日志信息\n") fmt.Printf(" t.Logf(format, args ...) # 格式化日志信息\n") fmt.Printf(" t.Skip(args ...) # 跳过测试\n") fmt.Printf(" t.Helper() # 标记为辅助函数\n") fmt.Println() } // demonstrateTableDrivenTests 演示表驱动测试 func demonstrateTableDrivenTests() { fmt.Println("3. 表驱动测试:") // 表驱动测试的优势 fmt.Printf(" 表驱动测试的优势:\n") fmt.Printf(" - 减少重复代码\n") fmt.Printf(" - 易于添加新的测试用例\n") fmt.Printf(" - 提高测试的可维护性\n") fmt.Printf(" - 清晰的测试数据结构\n") // 表驱动测试示例 fmt.Printf(" 表驱动测试示例:\n") fmt.Printf(" func TestAddTable(t *testing.T) {\n") fmt.Printf(" tests := []struct {\n") fmt.Printf(" name string\n") fmt.Printf(" a, b int\n") fmt.Printf(" expected int\n") fmt.Printf(" }{\n") fmt.Printf(" {\\\"positive\\\", 2, 3, 5},\n") fmt.Printf(" {\\\"negative\\\", -1, -2, -3},\n") fmt.Printf(" {\\\"zero\\\", 0, 5, 5},\n") fmt.Printf(" }\n") fmt.Printf(" \n") fmt.Printf(" for _, tt := range tests {\n") fmt.Printf(" t.Run(tt.name, func(t *testing.T) {\n") fmt.Printf(" result := Add(tt.a, tt.b)\n") fmt.Printf(" if result != tt.expected {\n") fmt.Printf(" t.Errorf(\\\"got %%d, want %%d\\\", result, tt.expected)\n") fmt.Printf(" }\n") fmt.Printf(" })\n") fmt.Printf(" }\n") fmt.Printf(" }\n") // 模拟运行表驱动测试 fmt.Printf(" 模拟运行表驱动测试:\n") mockT := &MockT{} TestAddTable(mockT) // 字符串处理的表驱动测试 fmt.Printf(" 字符串处理的表驱动测试:\n") mockT = &MockT{} TestStringOperations(mockT) // 错误处理的表驱动测试 fmt.Printf(" 错误处理的表驱动测试:\n") mockT = &MockT{} TestValidateInput(mockT) fmt.Println() } // demonstrateBenchmarkTesting 演示基准测试 func demonstrateBenchmarkTesting() { fmt.Println("4. 基准测试:") // 基准测试的概念 fmt.Printf(" 基准测试的概念:\n") fmt.Printf(" - 测量代码的性能\n") fmt.Printf(" - 比较不同实现的效率\n") fmt.Printf(" - 识别性能瓶颈\n") fmt.Printf(" - 验证优化效果\n") // 基准测试函数 fmt.Printf(" 基准测试函数:\n") fmt.Printf(" func BenchmarkStringConcat(b *testing.B) {\n") fmt.Printf(" for i := 0; i < b.N; i++ {\n") fmt.Printf(" _ = \\\"hello\\\" + \\\"world\\\"\n") fmt.Printf(" }\n") fmt.Printf(" }\n") // 模拟运行基准测试 fmt.Printf(" 模拟运行基准测试:\n") // 字符串连接基准测试 fmt.Printf(" 字符串连接性能比较:\n") runBenchmark("StringConcat", BenchmarkStringConcat) runBenchmark("StringBuffer", BenchmarkStringBuffer) runBenchmark("StringBuilder", BenchmarkStringBuilder) // 排序算法基准测试 fmt.Printf(" 排序算法性能比较:\n") runBenchmark("BubbleSort", BenchmarkBubbleSort) runBenchmark("QuickSort", BenchmarkQuickSort) runBenchmark("StandardSort", BenchmarkStandardSort) // 基准测试的运行参数 fmt.Printf(" 基准测试的运行参数:\n") fmt.Printf(" go test -bench=. # 运行所有基准测试\n") fmt.Printf(" go test -bench=BenchmarkAdd # 运行特定基准测试\n") fmt.Printf(" go test -bench=. -benchmem # 显示内存分配\n") fmt.Printf(" go test -bench=. -benchtime=10s # 设置运行时间\n") fmt.Printf(" go test -bench=. -count=5 # 运行多次\n") // 基准测试结果解读 fmt.Printf(" 基准测试结果解读:\n") fmt.Printf(" BenchmarkAdd-8 1000000000 0.50 ns/op 0 B/op 0 allocs/op\n") fmt.Printf(" │ │ │ │ │\n") fmt.Printf(" │ │ │ │ └─ 每次操作的分配次数\n") fmt.Printf(" │ │ │ └─ 每次操作分配的字节数\n") fmt.Printf(" │ │ └─ 每次操作的平均时间\n") fmt.Printf(" │ └─ 执行次数\n") fmt.Printf(" └─ 基准测试名称和CPU核心数\n") fmt.Println() } // demonstrateExampleTesting 演示示例测试 func demonstrateExampleTesting() { fmt.Println("5. 示例测试:") // 示例测试的概念 fmt.Printf(" 示例测试的概念:\n") fmt.Printf(" - 提供函数使用示例\n") fmt.Printf(" - 验证输出结果\n") fmt.Printf(" - 生成文档\n") fmt.Printf(" - 确保示例代码正确\n") // 示例测试函数 fmt.Printf(" 示例测试函数:\n") fmt.Printf(" func ExampleAdd() {\n") fmt.Printf(" result := Add(2, 3)\n") fmt.Printf(" fmt.Println(result)\n") fmt.Printf(" // Output: 5\n") fmt.Printf(" }\n") // 运行示例测试 fmt.Printf(" 运行示例测试:\n") fmt.Printf(" Add 函数示例:\n") ExampleAdd() fmt.Printf(" Divide 函数示例:\n") ExampleDivide() fmt.Printf(" StringReverse 函数示例:\n") ExampleStringReverse() // 示例测试的特点 fmt.Printf(" 示例测试的特点:\n") fmt.Printf(" 1. 函数名以 Example 开头\n") fmt.Printf(" 2. 使用 // Output: 注释指定期望输出\n") fmt.Printf(" 3. 可以使用 // Unordered output: 处理无序输出\n") fmt.Printf(" 4. 会在 go doc 中显示\n") fmt.Printf(" 5. 可以通过 go test 验证\n") fmt.Println() } // demonstrateTestingTools 演示测试工具和技巧 func demonstrateTestingTools() { fmt.Println("6. 测试工具和技巧:") // 测试覆盖率 fmt.Printf(" 测试覆盖率:\n") fmt.Printf(" go test -cover # 显示覆盖率\n") fmt.Printf(" go test -coverprofile=cover.out # 生成覆盖率文件\n") fmt.Printf(" go tool cover -html=cover.out # 生成HTML报告\n") fmt.Printf(" go tool cover -func=cover.out # 显示函数覆盖率\n") // 测试辅助函数 fmt.Printf(" 测试辅助函数:\n") fmt.Printf(" func assertEqual(t *testing.T, got, want interface{}) {\n") fmt.Printf(" t.Helper() // 标记为辅助函数\n") fmt.Printf(" if got != want {\n") fmt.Printf(" t.Errorf(\\\"got %%v, want %%v\\\", got, want)\n") fmt.Printf(" }\n") fmt.Printf(" }\n") // 模拟使用辅助函数 fmt.Printf(" 使用辅助函数:\n") mockT := &MockT{} TestWithHelpers(mockT) if mockT.failed { fmt.Printf(" ❌ 测试失败: %s\n", mockT.errorMsg) } else { fmt.Printf(" ✅ 测试通过\n") } // 子测试 fmt.Printf(" 子测试:\n") fmt.Printf(" t.Run(\\\"subtest\\\", func(t *testing.T) {\n") fmt.Printf(" // 子测试代码\n") fmt.Printf(" })\n") // 并行测试 fmt.Printf(" 并行测试:\n") fmt.Printf(" func TestParallel(t *testing.T) {\n") fmt.Printf(" t.Parallel() // 标记为并行测试\n") fmt.Printf(" // 测试代码\n") fmt.Printf(" }\n") // 测试设置和清理 fmt.Printf(" 测试设置和清理:\n") fmt.Printf(" func TestMain(m *testing.M) {\n") fmt.Printf(" setup() // 全局设置\n") fmt.Printf(" code := m.Run()\n") fmt.Printf(" teardown() // 全局清理\n") fmt.Printf(" os.Exit(code)\n") fmt.Printf(" }\n") // 跳过测试 fmt.Printf(" 跳过测试:\n") fmt.Printf(" if testing.Short() {\n") fmt.Printf(" t.Skip(\\\"跳过长时间运行的测试\\\")\n") fmt.Printf(" }\n") // 临时目录 fmt.Printf(" 临时目录:\n") fmt.Printf(" tmpDir := t.TempDir() // 创建临时目录\n") fmt.Printf(" // 测试结束后自动清理\n") fmt.Println() } // demonstrateTestingBestPractices 演示测试的最佳实践 func demonstrateTestingBestPractices() { fmt.Println("7. 测试的最佳实践:") // 测试命名 fmt.Printf(" 测试命名:\n") fmt.Printf(" 1. 使用描述性的测试名称\n") fmt.Printf(" 2. 包含被测试的功能和场景\n") fmt.Printf(" 3. 使用一致的命名约定\n") fmt.Printf(" \n") fmt.Printf(" 好的命名:\n") fmt.Printf(" TestAdd_PositiveNumbers\n") fmt.Printf(" TestDivide_ByZero_ReturnsError\n") fmt.Printf(" TestUser_Create_ValidInput\n") // 测试组织 fmt.Printf(" 测试组织:\n") fmt.Printf(" 1. 每个源文件对应一个测试文件\n") fmt.Printf(" 2. 按功能分组测试\n") fmt.Printf(" 3. 使用子测试组织复杂场景\n") fmt.Printf(" 4. 保持测试的独立性\n") // 测试数据 fmt.Printf(" 测试数据:\n") fmt.Printf(" 1. 使用表驱动测试处理多个用例\n") fmt.Printf(" 2. 包含边界条件和异常情况\n") fmt.Printf(" 3. 使用有意义的测试数据\n") fmt.Printf(" 4. 避免硬编码的魔法数字\n") // 断言 fmt.Printf(" 断言:\n") fmt.Printf(" 1. 使用清晰的错误消息\n") fmt.Printf(" 2. 一个测试只验证一个行为\n") fmt.Printf(" 3. 优先使用 Errorf 而不是 Error\n") fmt.Printf(" 4. 在必要时使用 Fatal 停止测试\n") // 测试覆盖率 fmt.Printf(" 测试覆盖率:\n") fmt.Printf(" 1. 追求高覆盖率但不盲目追求100%%\n") fmt.Printf(" 2. 关注重要的业务逻辑\n") fmt.Printf(" 3. 测试边界条件和错误路径\n") fmt.Printf(" 4. 使用覆盖率工具识别遗漏\n") // 性能考虑 fmt.Printf(" 性能考虑:\n") fmt.Printf(" 1. 避免在测试中进行复杂计算\n") fmt.Printf(" 2. 使用并行测试提高速度\n") fmt.Printf(" 3. 合理使用测试缓存\n") fmt.Printf(" 4. 避免不必要的外部依赖\n") // 测试维护 fmt.Printf(" 测试维护:\n") fmt.Printf(" 1. 保持测试代码的简洁\n") fmt.Printf(" 2. 定期重构测试代码\n") fmt.Printf(" 3. 及时更新过时的测试\n") fmt.Printf(" 4. 删除无用的测试\n") // 常见陷阱 fmt.Printf(" 常见陷阱:\n") fmt.Printf(" 1. 测试依赖外部状态\n") fmt.Printf(" 2. 测试之间相互依赖\n") fmt.Printf(" 3. 忽略错误处理的测试\n") fmt.Printf(" 4. 过度复杂的测试逻辑\n") fmt.Printf(" 5. 不稳定的测试(flaky tests)\n") fmt.Println() } // ========== 被测试的函数 ========== // Add 计算两个整数的和 func Add(a, b int) int { return a + b } // Divide 计算两个数的商 func Divide(a, b float64) (float64, error) { if b == 0 { return 0, fmt.Errorf("division by zero") } return a / b, nil } // IsPrime 判断是否为质数 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 } // StringReverse 反转字符串 func StringReverse(s string) string { runes := []rune(s) for i, j := 0, len(runes)-1; i < j; i, j = i+1, j-1 { runes[i], runes[j] = runes[j], runes[i] } return string(runes) } // Capitalize 将字符串首字母大写 func Capitalize(s string) string { if len(s) == 0 { return s } return strings.ToUpper(s[:1]) + strings.ToLower(s[1:]) } // ValidateInput 验证输入 func ValidateInput(input string) error { if len(input) == 0 { return fmt.Errorf("input cannot be empty") } if len(input) > 100 { return fmt.Errorf("input too long") } return nil } // ========== 模拟的 testing.T 和 testing.B ========== // MockT 模拟 testing.T 类型 type MockT struct { failed bool errorMsg string logs []string } func (m *MockT) Error(args ...interface{}) { m.failed = true m.errorMsg = fmt.Sprint(args...) } func (m *MockT) Errorf(format string, args ...interface{}) { m.failed = true m.errorMsg = fmt.Sprintf(format, args...) } func (m *MockT) Fatal(args ...interface{}) { m.failed = true m.errorMsg = fmt.Sprint(args...) } func (m *MockT) Fatalf(format string, args ...interface{}) { m.failed = true m.errorMsg = fmt.Sprintf(format, args...) } func (m *MockT) Log(args ...interface{}) { m.logs = append(m.logs, fmt.Sprint(args...)) } func (m *MockT) Logf(format string, args ...interface{}) { m.logs = append(m.logs, fmt.Sprintf(format, args...)) } func (m *MockT) Helper() { // 标记为辅助函数 } func (m *MockT) Run(name string, f func(*MockT)) bool { fmt.Printf(" 运行子测试: %s\n", name) subT := &MockT{} f(subT) if subT.failed { fmt.Printf(" ❌ 失败: %s\n", subT.errorMsg) return false } else { fmt.Printf(" ✅ 通过\n") return true } } // MockB 模拟 testing.B 类型 type MockB struct { N int } func (b *MockB) ResetTimer() {} func (b *MockB) ReportAllocs() {} // ========== 测试函数示例 ========== // TestAdd 测试 Add 函数 func TestAdd(t *MockT) { result := Add(2, 3) expected := 5 if result != expected { t.Errorf("Add(2, 3) = %d; want %d", result, expected) } } // TestDivide 测试 Divide 函数 func TestDivide(t *MockT) { // 正常情况 result, err := Divide(10, 2) if err != nil { t.Errorf("Divide(10, 2) returned error: %v", err) return } if result != 5 { t.Errorf("Divide(10, 2) = %f; want 5", result) } // 除零情况 _, err = Divide(10, 0) if err == nil { t.Error("Divide(10, 0) should return error") } } // TestIsPrime 测试 IsPrime 函数 func TestIsPrime(t *MockT) { tests := []struct { n int expected bool }{ {2, true}, {3, true}, {4, false}, {17, true}, {25, false}, {1, false}, {0, false}, {-1, false}, } for _, tt := range tests { result := IsPrime(tt.n) if result != tt.expected { t.Errorf("IsPrime(%d) = %t; want %t", tt.n, result, tt.expected) } } } // TestAddTable 表驱动测试示例 func TestAddTable(t *MockT) { tests := []struct { name string a, b int expected int }{ {"positive numbers", 2, 3, 5}, {"negative numbers", -1, -2, -3}, {"mixed numbers", -1, 2, 1}, {"zero", 0, 5, 5}, } for _, tt := range tests { t.Run(tt.name, func(subT *MockT) { result := Add(tt.a, tt.b) if result != tt.expected { subT.Errorf("Add(%d, %d) = %d; want %d", tt.a, tt.b, result, tt.expected) } }) } } // TestStringOperations 字符串操作测试 func TestStringOperations(t *MockT) { tests := []struct { name string input string expected string }{ {"normal string", "hello", "Hello"}, {"empty string", "", ""}, {"single char", "a", "A"}, {"already capitalized", "Hello", "Hello"}, } for _, tt := range tests { t.Run(tt.name, func(subT *MockT) { result := Capitalize(tt.input) if result != tt.expected { subT.Errorf("Capitalize(%q) = %q; want %q", tt.input, result, tt.expected) } }) } } // TestValidateInput 输入验证测试 func TestValidateInput(t *MockT) { tests := []struct { name string input string wantError bool }{ {"valid input", "hello", false}, {"empty input", "", true}, {"too long input", strings.Repeat("a", 101), true}, {"max length input", strings.Repeat("a", 100), false}, } for _, tt := range tests { t.Run(tt.name, func(subT *MockT) { err := ValidateInput(tt.input) if (err != nil) != tt.wantError { subT.Errorf("ValidateInput(%q) error = %v; wantError %t", tt.input, err, tt.wantError) } }) } } // TestWithHelpers 使用辅助函数的测试 func TestWithHelpers(t *MockT) { assertEqual := func(t *MockT, got, want interface{}) { t.Helper() if got != want { t.Errorf("got %v, want %v", got, want) } } // 使用辅助函数进行断言 assertEqual(t, Add(2, 3), 5) assertEqual(t, Capitalize("hello"), "Hello") result, err := Divide(10, 2) if err != nil { t.Errorf("unexpected error: %v", err) return } assertEqual(t, result, 5.0) } // ========== 基准测试函数 ========== // BenchmarkStringConcat 字符串连接基准测试 func BenchmarkStringConcat(b *MockB) { for i := 0; i < b.N; i++ { _ = "hello" + "world" + "golang" + "benchmark" } } // BenchmarkStringBuffer 字符串缓冲区基准测试 func BenchmarkStringBuffer(b *MockB) { for i := 0; i < b.N; i++ { var buffer strings.Builder buffer.WriteString("hello") buffer.WriteString("world") buffer.WriteString("golang") buffer.WriteString("benchmark") _ = buffer.String() } } // BenchmarkStringBuilder 字符串构建器基准测试 func BenchmarkStringBuilder(b *MockB) { for i := 0; i < b.N; i++ { parts := []string{"hello", "world", "golang", "benchmark"} _ = strings.Join(parts, "") } } // BenchmarkBubbleSort 冒泡排序基准测试 func BenchmarkBubbleSort(b *MockB) { data := []int{64, 34, 25, 12, 22, 11, 90} for i := 0; i < b.N; i++ { bubbleSort(append([]int(nil), data...)) } } // BenchmarkQuickSort 快速排序基准测试 func BenchmarkQuickSort(b *MockB) { data := []int{64, 34, 25, 12, 22, 11, 90} for i := 0; i < b.N; i++ { quickSort(append([]int(nil), data...)) } } // BenchmarkStandardSort 标准排序基准测试 func BenchmarkStandardSort(b *MockB) { data := []int{64, 34, 25, 12, 22, 11, 90} for i := 0; i < b.N; i++ { sort.Ints(append([]int(nil), data...)) } } // ========== 示例测试函数 ========== // ExampleAdd Add 函数的示例 func ExampleAdd() { result := Add(2, 3) fmt.Println(result) // Output: 5 } // ExampleDivide Divide 函数的示例 func ExampleDivide() { result, err := Divide(10, 2) if err != nil { fmt.Printf("Error: %v", err) return } fmt.Printf("%.1f", result) // Output: 5.0 } // ExampleStringReverse StringReverse 函数的示例 func ExampleStringReverse() { result := StringReverse("hello") fmt.Println(result) // Output: olleh } // ========== 辅助函数 ========== // runBenchmark 运行基准测试 func runBenchmark(name string, benchFunc func(*MockB)) { b := &MockB{N: 1000000} start := time.Now() benchFunc(b) duration := time.Since(start) nsPerOp := duration.Nanoseconds() / int64(b.N) fmt.Printf(" %s: %d ns/op\n", name, nsPerOp) } // bubbleSort 冒泡排序 func bubbleSort(arr []int) { n := len(arr) for i := 0; i < n-1; i++ { for j := 0; j < n-i-1; j++ { if arr[j] > arr[j+1] { arr[j], arr[j+1] = arr[j+1], arr[j] } } } } // quickSort 快速排序 func quickSort(arr []int) { if len(arr) < 2 { return } pivot := partition(arr) quickSort(arr[:pivot]) quickSort(arr[pivot+1:]) } // partition 分区函数 func partition(arr []int) int { pivot := arr[len(arr)-1] i := -1 for j := 0; j < len(arr)-1; j++ { if arr[j] <= pivot { i++ arr[i], arr[j] = arr[j], arr[i] } } arr[i+1], arr[len(arr)-1] = arr[len(arr)-1], arr[i+1] return i + 1 } /* 运行这个程序: go run 04-testing.go 实际测试文件示例(calculator_test.go): package calculator import "testing" func TestAdd(t *testing.T) { result := Add(2, 3) expected := 5 if result != expected { t.Errorf("Add(2, 3) = %d; want %d", result, expected) } } func TestAddTable(t *testing.T) { tests := []struct { name string a, b int expected int }{ {"positive numbers", 2, 3, 5}, {"negative numbers", -1, -2, -3}, {"mixed numbers", -1, 2, 1}, {"zero", 0, 5, 5}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { result := Add(tt.a, tt.b) if result != tt.expected { t.Errorf("got %d, want %d", result, tt.expected) } }) } } func BenchmarkStringConcat(b *testing.B) { for i := 0; i < b.N; i++ { _ = "hello" + "world" } } func ExampleAdd() { result := Add(2, 3) fmt.Println(result) // Output: 5 } 运行测试命令: go test # 运行当前包的所有测试 go test -v # 详细输出 go test -run TestAdd # 运行特定测试 go test -bench=. # 运行基准测试 go test -cover # 显示覆盖率 go test ./... # 运行所有子包的测试 测试的核心概念: 1. 单元测试:验证单个函数或方法的正确性 2. 表驱动测试:使用测试数据表驱动测试执行 3. 基准测试:测量代码的性能和内存使用 4. 示例测试:提供函数使用示例并验证输出 测试的最佳实践: 1. 使用描述性的测试名称 2. 保持测试的独立性 3. 测试边界条件和错误情况 4. 使用表驱动测试处理多个用例 5. 编写清晰的错误消息 6. 保持高的测试覆盖率 7. 定期重构和维护测试代码 注意事项: 1. 测试文件必须以 _test.go 结尾 2. 测试函数必须以 Test 开头 3. 基准测试函数必须以 Benchmark 开头 4. 示例测试函数必须以 Example 开头 5. 使用 t.Helper() 标记辅助函数 6. 合理使用并行测试提高效率 */