Testing Guide - zhoudm1743/go-util GitHub Wiki

本指南将帮助您全面了解 Go-Util 项目的测试策略、测试编写规范和最佳实践。

🎯 测试策略概览

测试金字塔

    /\
   /  \     E2E 测试 (5%)
  /____\    集成测试 (15%)
 /______\   单元测试 (80%)
  • 单元测试: 测试单个函数/方法的功能
  • 集成测试: 测试模块间的交互
  • 端到端测试: 测试完整的用户场景

测试原则

  • 快速: 单元测试应该在毫秒级完成
  • 独立: 测试之间不应相互依赖
  • 可重复: 多次运行结果一致
  • 自验证: 测试结果明确(通过/失败)
  • 及时: 测试应该在代码变更时立即运行

🧪 单元测试规范

1. 测试文件组织

// 文件结构
types_str.go       // 源码文件
types_str_test.go  // 测试文件

2. 测试函数命名

// 标准命名格式: TestFunctionName_Scenario
func TestXStr_Upper_BasicConversion(t *testing.T) {
    // 测试基础大写转换
}

func TestXStr_Upper_EmptyString(t *testing.T) {
    // 测试空字符串场景
}

func TestXStr_Upper_UnicodeCharacters(t *testing.T) {
    // 测试Unicode字符场景
}

3. 表驱动测试模式

func TestXStr_IsEmail(t *testing.T) {
    tests := []struct {
        name     string
        input    string
        expected bool
        reason   string
    }{
        {
            name:     "有效邮箱",
            input:    "[email protected]",
            expected: true,
            reason:   "标准邮箱格式",
        },
        {
            name:     "无效邮箱_缺少@",
            input:    "userexample.com",
            expected: false,
            reason:   "缺少@符号",
        },
        {
            name:     "无效邮箱_缺少域名",
            input:    "user@",
            expected: false,
            reason:   "缺少域名部分",
        },
        {
            name:     "空字符串",
            input:    "",
            expected: false,
            reason:   "空字符串不是有效邮箱",
        },
        {
            name:     "复杂邮箱",
            input:    "[email protected]",
            expected: true,
            reason:   "复杂但有效的邮箱格式",
        },
    }

    for _, tt := range tests {
        t.Run(tt.name, func(t *testing.T) {
            result := util.Str(tt.input).IsEmail()
            if result != tt.expected {
                t.Errorf("IsEmail(%q) = %v, want %v (%s)", 
                    tt.input, result, tt.expected, tt.reason)
            }
        })
    }
}

4. 测试辅助函数

// 测试辅助函数
func assertStringEqual(t *testing.T, actual, expected string) {
    t.Helper()
    if actual != expected {
        t.Errorf("got %q, want %q", actual, expected)
    }
}

func assertStringContains(t *testing.T, str, substr string) {
    t.Helper()
    if !strings.Contains(str, substr) {
        t.Errorf("string %q does not contain %q", str, substr)
    }
}

func assertNoError(t *testing.T, err error) {
    t.Helper()
    if err != nil {
        t.Errorf("unexpected error: %v", err)
    }
}

func assertError(t *testing.T, err error, expectedMsg string) {
    t.Helper()
    if err == nil {
        t.Error("expected error but got none")
        return
    }
    if !strings.Contains(err.Error(), expectedMsg) {
        t.Errorf("error %q does not contain %q", err.Error(), expectedMsg)
    }
}

// 使用示例
func TestXStr_ToInt_ValidNumber(t *testing.T) {
    result, err := util.Str("123").ToInt()
    assertNoError(t, err)
    if result != 123 {
        t.Errorf("ToInt() = %d, want 123", result)
    }
}

5. 边界条件测试

func TestXStr_Slice_BoundaryConditions(t *testing.T) {
    tests := []struct {
        name     string
        input    string
        start    int
        end      int
        expected string
        hasError bool
    }{
        // 正常情况
        {
            name:     "正常切片",
            input:    "hello world",
            start:    0,
            end:      5,
            expected: "hello",
            hasError: false,
        },
        // 边界情况
        {
            name:     "起始位置为0",
            input:    "hello",
            start:    0,
            end:      0,
            expected: "",
            hasError: false,
        },
        {
            name:     "结束位置等于长度",
            input:    "hello",
            start:    0,
            end:      5,
            expected: "hello",
            hasError: false,
        },
        {
            name:     "空字符串",
            input:    "",
            start:    0,
            end:      0,
            expected: "",
            hasError: false,
        },
        // 错误情况
        {
            name:     "起始位置超出范围",
            input:    "hello",
            start:    10,
            end:      15,
            expected: "",
            hasError: true,
        },
        {
            name:     "结束位置超出范围",
            input:    "hello",
            start:    0,
            end:      10,
            expected: "",
            hasError: true,
        },
        {
            name:     "起始位置大于结束位置",
            input:    "hello",
            start:    3,
            end:      1,
            expected: "",
            hasError: true,
        },
    }

    for _, tt := range tests {
        t.Run(tt.name, func(t *testing.T) {
            result, err := util.Str(tt.input).Slice(tt.start, tt.end)
            
            if tt.hasError {
                if err == nil {
                    t.Errorf("expected error but got none")
                }
                return
            }
            
            assertNoError(t, err)
            assertStringEqual(t, result, tt.expected)
        })
    }
}

🔗 集成测试

1. 模块间交互测试

func TestStringArrayIntegration(t *testing.T) {
    // 测试字符串和数组工具的集成使用
    userEmails := []string{
        "  [email protected]  ",
        "[email protected]",
        "invalid-email",
        "  [email protected]  ",
    }
    
    // 清理和验证邮箱
    validEmails := util.ArraysFromSlice(userEmails).
        Map(func(email string) string {
            return util.Str(email).Trim().Lower().String()
        }).
        Filter(func(email string) bool {
            return util.Str(email).IsEmail()
        }).
        ToSlice()
    
    expected := []string{
        "[email protected]",
        "[email protected]",
        "[email protected]",
    }
    
    if len(validEmails) != len(expected) {
        t.Errorf("expected %d valid emails, got %d", len(expected), len(validEmails))
    }
    
    for i, email := range validEmails {
        if email != expected[i] {
            t.Errorf("email[%d] = %q, want %q", i, email, expected[i])
        }
    }
}

2. JSON 操作集成测试

func TestJSONOperationIntegration(t *testing.T) {
    // 测试复杂的JSON操作场景
    jsonData := `{
        "users": [
            {"name": "Alice", "email": "[email protected]", "age": 25},
            {"name": "Bob", "email": "[email protected]", "age": 30}
        ],
        "metadata": {
            "total": 2,
            "page": 1
        }
    }`
    
    // 使用 JSONx 进行操作
    j, err := util.ParseJSON(jsonData)
    assertNoError(t, err)
    
    // 提取用户邮箱
    emails := j.Get("users").Array().Map(func(user *util.JSON) string {
        return user.Get("email").String()
    })
    
    // 验证邮箱格式
    validEmails := util.ArraysFromSlice(emails).
        Filter(func(email string) bool {
            return util.Str(email).IsEmail()
        }).
        ToSlice()
    
    if len(validEmails) != 2 {
        t.Errorf("expected 2 valid emails, got %d", len(validEmails))
    }
    
    // 更新用户年龄
    j.Get("users").Array().ForEach(func(i int, user *util.JSON) bool {
        currentAge := user.Get("age").Int()
        user.Set("age", currentAge+1)
        return true
    })
    
    // 验证更新
    aliceAge := j.Get("users.0.age").Int()
    if aliceAge != 26 {
        t.Errorf("Alice's age should be 26, got %d", aliceAge)
    }
}

3. 时间处理集成测试

func TestTimeProcessingIntegration(t *testing.T) {
    // 测试时间处理的完整流程
    timestamps := []string{
        "2023-12-25T10:30:00Z",
        "2023-12-25T15:45:00+08:00",
        "invalid-time",
        "2023-12-26T08:00:00Z",
    }
    
    // 解析和处理时间
    validTimes := util.ArraysFromSlice(timestamps).
        Map(func(ts string) *util.XTime {
            time, err := util.ParseTime(ts)
            if err != nil {
                return nil
            }
            return time
        }).
        Filter(func(time *util.XTime) bool {
            return time != nil
        }).
        Map(func(time *util.XTime) *util.XTime {
            return time.ToUTC()
        }).
        SortWith(func(a, b *util.XTime) bool {
            return a.Before(b)
        }).
        ToSlice()
    
    if len(validTimes) != 3 {
        t.Errorf("expected 3 valid times, got %d", len(validTimes))
    }
    
    // 验证排序结果
    if !validTimes[0].Before(validTimes[1]) {
        t.Error("times are not properly sorted")
    }
    
    // 计算时间范围
    timeRange := util.NewTimeRange(validTimes[0], validTimes[len(validTimes)-1])
    duration := timeRange.Duration()
    
    if duration <= 0 {
        t.Error("time range duration should be positive")
    }
}

⚡ 性能测试

1. 基准测试

func BenchmarkXStr_Operations(b *testing.B) {
    testString := "  Hello World, This is a Test String!  "
    
    b.Run("Single_Operation", func(b *testing.B) {
        b.ResetTimer()
        b.ReportAllocs()
        
        for i := 0; i < b.N; i++ {
            _ = util.Str(testString).Upper().String()
        }
    })
    
    b.Run("Chained_Operations", func(b *testing.B) {
        b.ResetTimer()
        b.ReportAllocs()
        
        for i := 0; i < b.N; i++ {
            result := util.Str(testString).
                Trim().
                Lower().
                ReplaceRegex(`\s+`, "_").
                Snake2Camel().
                String()
            _ = result
        }
    })
    
    b.Run("Memory_Allocation", func(b *testing.B) {
        b.ResetTimer()
        b.ReportAllocs()
        
        for i := 0; i < b.N; i++ {
            str := util.Str(testString)
            for j := 0; j < 10; j++ {
                str = str.Upper().Lower()
            }
            _ = str.String()
        }
    })
}

func BenchmarkXArray_Operations(b *testing.B) {
    data := make([]int, 10000)
    for i := range data {
        data[i] = i
    }
    
    b.Run("Filter", func(b *testing.B) {
        b.ResetTimer()
        b.ReportAllocs()
        
        for i := 0; i < b.N; i++ {
            _ = util.ArraysFromSlice(data).
                Filter(func(n int) bool { return n%2 == 0 }).
                ToSlice()
        }
    })
    
    b.Run("Map", func(b *testing.B) {
        b.ResetTimer()
        b.ReportAllocs()
        
        for i := 0; i < b.N; i++ {
            _ = util.ArraysFromSlice(data).
                Map(func(n int) int { return n * 2 }).
                ToSlice()
        }
    })
    
    b.Run("Chained", func(b *testing.B) {
        b.ResetTimer()
        b.ReportAllocs()
        
        for i := 0; i < b.N; i++ {
            _ = util.ArraysFromSlice(data).
                Filter(func(n int) bool { return n%2 == 0 }).
                Map(func(n int) int { return n * 2 }).
                Take(100).
                ToSlice()
        }
    })
}

2. 内存测试

func TestMemoryUsage(t *testing.T) {
    // 测试内存使用情况
    const iterations = 1000
    
    var m1, m2 runtime.MemStats
    runtime.GC()
    runtime.ReadMemStats(&m1)
    
    // 执行操作
    for i := 0; i < iterations; i++ {
        data := make([]string, 100)
        for j := range data {
            data[j] = fmt.Sprintf("item_%d", j)
        }
        
        _ = util.ArraysFromSlice(data).
            Map(func(s string) string {
                return util.Str(s).Upper().String()
            }).
            Filter(func(s string) bool {
                return util.Str(s).Contains("ITEM")
            }).
            ToSlice()
    }
    
    runtime.GC()
    runtime.ReadMemStats(&m2)
    
    allocsPerOp := (m2.Mallocs - m1.Mallocs) / iterations
    bytesPerOp := (m2.TotalAlloc - m1.TotalAlloc) / iterations
    
    t.Logf("Memory per operation: %d allocs, %d bytes", allocsPerOp, bytesPerOp)
    
    // 设置合理的内存使用阈值
    if allocsPerOp > 1000 {
        t.Errorf("Too many allocations per operation: %d", allocsPerOp)
    }
    
    if bytesPerOp > 100000 {
        t.Errorf("Too much memory per operation: %d bytes", bytesPerOp)
    }
}

3. 并发安全测试

func TestConcurrencySafety(t *testing.T) {
    const goroutines = 100
    const operations = 1000
    
    // 测试 SafeMap 的并发安全性
    safeMap := util.NewSafeMap[string, int]()
    
    var wg sync.WaitGroup
    wg.Add(goroutines)
    
    // 启动多个goroutine进行并发操作
    for i := 0; i < goroutines; i++ {
        go func(id int) {
            defer wg.Done()
            
            for j := 0; j < operations; j++ {
                key := fmt.Sprintf("key_%d_%d", id, j)
                value := id*operations + j
                
                // 写操作
                safeMap.Set(key, value)
                
                // 读操作
                if val, exists := safeMap.Get(key); exists {
                    if val != value {
                        t.Errorf("Expected %d, got %d for key %s", value, val, key)
                    }
                }
                
                // 删除操作
                if j%10 == 0 {
                    safeMap.Delete(key)
                }
            }
        }(i)
    }
    
    wg.Wait()
    
    // 验证最终状态
    finalSize := safeMap.Size()
    t.Logf("Final map size: %d", finalSize)
    
    // 应该有一些数据被保留(未被删除的)
    if finalSize == 0 {
        t.Error("SafeMap should not be empty after concurrent operations")
    }
}

🧩 Mock 和 Stub

1. 接口 Mock

// 定义接口
type UserRepository interface {
    GetUser(id string) (*User, error)
    SaveUser(user *User) error
}

// Mock 实现
type MockUserRepository struct {
    users map[string]*User
    err   error
}

func NewMockUserRepository() *MockUserRepository {
    return &MockUserRepository{
        users: make(map[string]*User),
    }
}

func (m *MockUserRepository) GetUser(id string) (*User, error) {
    if m.err != nil {
        return nil, m.err
    }
    
    user, exists := m.users[id]
    if !exists {
        return nil, errors.New("user not found")
    }
    
    return user, nil
}

func (m *MockUserRepository) SaveUser(user *User) error {
    if m.err != nil {
        return m.err
    }
    
    m.users[user.ID] = user
    return nil
}

func (m *MockUserRepository) SetError(err error) {
    m.err = err
}

func (m *MockUserRepository) AddUser(user *User) {
    m.users[user.ID] = user
}

// 使用 Mock 进行测试
func TestUserService_ProcessUser(t *testing.T) {
    mockRepo := NewMockUserRepository()
    service := NewUserService(mockRepo)
    
    // 测试成功场景
    t.Run("Success", func(t *testing.T) {
        user := &User{ID: "1", Name: "Alice", Email: "[email protected]"}
        mockRepo.AddUser(user)
        
        result, err := service.ProcessUser("1")
        assertNoError(t, err)
        assertStringEqual(t, result.Name, "Alice")
    })
    
    // 测试错误场景
    t.Run("UserNotFound", func(t *testing.T) {
        _, err := service.ProcessUser("nonexistent")
        assertError(t, err, "user not found")
    })
    
    // 测试仓库错误
    t.Run("RepositoryError", func(t *testing.T) {
        mockRepo.SetError(errors.New("database error"))
        _, err := service.ProcessUser("1")
        assertError(t, err, "database error")
    })
}

2. HTTP 客户端 Mock

// HTTP 客户端接口
type HTTPClient interface {
    Get(url string) (*http.Response, error)
    Post(url string, body io.Reader) (*http.Response, error)
}

// Mock HTTP 客户端
type MockHTTPClient struct {
    responses map[string]*http.Response
    errors    map[string]error
}

func NewMockHTTPClient() *MockHTTPClient {
    return &MockHTTPClient{
        responses: make(map[string]*http.Response),
        errors:    make(map[string]error),
    }
}

func (m *MockHTTPClient) Get(url string) (*http.Response, error) {
    if err, exists := m.errors[url]; exists {
        return nil, err
    }
    
    if resp, exists := m.responses[url]; exists {
        return resp, nil
    }
    
    return nil, errors.New("no mock response configured")
}

func (m *MockHTTPClient) SetResponse(url string, statusCode int, body string) {
    m.responses[url] = &http.Response{
        StatusCode: statusCode,
        Body:       io.NopCloser(strings.NewReader(body)),
    }
}

func (m *MockHTTPClient) SetError(url string, err error) {
    m.errors[url] = err
}

// 使用示例
func TestAPIClient_GetUserProfile(t *testing.T) {
    mockClient := NewMockHTTPClient()
    apiClient := NewAPIClient(mockClient)
    
    t.Run("Success", func(t *testing.T) {
        responseBody := `{"id": "123", "name": "Alice"}`
        mockClient.SetResponse("https://api.example.com/users/123", 200, responseBody)
        
        profile, err := apiClient.GetUserProfile("123")
        assertNoError(t, err)
        assertStringEqual(t, profile.Name, "Alice")
    })
    
    t.Run("NetworkError", func(t *testing.T) {
        mockClient.SetError("https://api.example.com/users/456", errors.New("network error"))
        
        _, err := apiClient.GetUserProfile("456")
        assertError(t, err, "network error")
    })
}

🔄 测试生命周期

1. SetUp 和 TearDown

func TestMain(m *testing.M) {
    // 全局设置
    setup()
    
    // 运行测试
    code := m.Run()
    
    // 全局清理
    teardown()
    
    os.Exit(code)
}

func setup() {
    // 初始化测试环境
    log.Println("Setting up test environment...")
    
    // 创建临时目录
    os.MkdirAll("testdata/temp", 0755)
    
    // 初始化数据库连接
    initTestDatabase()
}

func teardown() {
    // 清理测试环境
    log.Println("Cleaning up test environment...")
    
    // 删除临时文件
    os.RemoveAll("testdata/temp")
    
    // 关闭数据库连接
    closeTestDatabase()
}

// 测试套件结构
type TestSuite struct {
    tempDir string
    db      *sql.DB
}

func (ts *TestSuite) SetUpTest(t *testing.T) {
    // 每个测试前的设置
    var err error
    ts.tempDir, err = os.MkdirTemp("", "test_")
    if err != nil {
        t.Fatalf("Failed to create temp dir: %v", err)
    }
    
    ts.db, err = sql.Open("sqlite3", ":memory:")
    if err != nil {
        t.Fatalf("Failed to open database: %v", err)
    }
}

func (ts *TestSuite) TearDownTest(t *testing.T) {
    // 每个测试后的清理
    if ts.tempDir != "" {
        os.RemoveAll(ts.tempDir)
    }
    
    if ts.db != nil {
        ts.db.Close()
    }
}

2. 子测试和并行测试

func TestStringOperations(t *testing.T) {
    t.Run("BasicOperations", func(t *testing.T) {
        t.Parallel() // 并行运行
        
        t.Run("Upper", func(t *testing.T) {
            result := util.Str("hello").Upper().String()
            assertStringEqual(t, result, "HELLO")
        })
        
        t.Run("Lower", func(t *testing.T) {
            result := util.Str("HELLO").Lower().String()
            assertStringEqual(t, result, "hello")
        })
        
        t.Run("Trim", func(t *testing.T) {
            result := util.Str("  hello  ").Trim().String()
            assertStringEqual(t, result, "hello")
        })
    })
    
    t.Run("ValidationOperations", func(t *testing.T) {
        t.Parallel() // 并行运行
        
        t.Run("IsEmail", func(t *testing.T) {
            if !util.Str("[email protected]").IsEmail() {
                t.Error("Valid email should return true")
            }
        })
        
        t.Run("IsNumeric", func(t *testing.T) {
            if !util.Str("12345").IsNumeric() {
                t.Error("Numeric string should return true")
            }
        })
    })
}

📊 测试覆盖率

1. 生成覆盖率报告

# 运行测试并生成覆盖率
go test -v -cover -coverprofile=coverage.out ./...

# 查看覆盖率概要
go tool cover -func=coverage.out

# 生成 HTML 覆盖率报告
go tool cover -html=coverage.out -o coverage.html

# 设置覆盖率阈值
go test -cover -coverprofile=coverage.out ./... && \
go tool cover -func=coverage.out | grep "total:" | \
awk '{if ($3+0 < 80) exit 1}'

2. 覆盖率配置

// coverage_test.go
//go:build coverage
// +build coverage

package util

import (
    "testing"
    "os"
)

func TestCoverage(t *testing.T) {
    // 确保所有导出函数都有测试覆盖
    requiredCoverage := map[string]bool{
        "Str":          false,
        "Arrays":       false,
        "Maps":         false,
        "Now":          false,
        "ParseJSON":    false,
    }
    
    // 这里可以通过反射检查所有导出函数是否被测试覆盖
    // 具体实现依据项目需求
}

func TestMain(m *testing.M) {
    // 设置覆盖率相关环境变量
    if os.Getenv("COVERAGE") != "" {
        // 启用覆盖率收集
        setupCoverageCollection()
    }
    
    code := m.Run()
    
    if os.Getenv("COVERAGE") != "" {
        // 处理覆盖率数据
        processCoverageData()
    }
    
    os.Exit(code)
}

🐛 测试调试

1. 调试技巧

func TestDebugExample(t *testing.T) {
    // 使用 t.Log 输出调试信息
    t.Logf("Testing with input: %q", "test input")
    
    // 条件性跳过测试
    if testing.Short() {
        t.Skip("Skipping test in short mode")
    }
    
    // 标记测试失败但继续执行
    result := performOperation()
    if result != expected {
        t.Errorf("Got %v, want %v", result, expected)
    }
    
    // 立即停止测试
    if criticalError {
        t.Fatalf("Critical error occurred: %v", err)
    }
    
    // 使用 testify 进行断言(可选)
    // assert.Equal(t, expected, result, "Values should be equal")
    // require.NoError(t, err, "Should not return error")
}

2. 测试数据管理

// testdata 目录结构
// testdata/
//   ├── valid_emails.txt
//   ├── invalid_emails.txt
//   ├── sample.json
//   └── large_dataset.csv

func loadTestData(t *testing.T, filename string) []byte {
    t.Helper()
    
    data, err := os.ReadFile(filepath.Join("testdata", filename))
    if err != nil {
        t.Fatalf("Failed to load test data %s: %v", filename, err)
    }
    
    return data
}

func TestWithTestData(t *testing.T) {
    // 加载测试数据
    validEmails := strings.Split(string(loadTestData(t, "valid_emails.txt")), "\n")
    invalidEmails := strings.Split(string(loadTestData(t, "invalid_emails.txt")), "\n")
    
    // 测试有效邮箱
    for _, email := range validEmails {
        if email = strings.TrimSpace(email); email != "" {
            if !util.Str(email).IsEmail() {
                t.Errorf("Email %q should be valid", email)
            }
        }
    }
    
    // 测试无效邮箱
    for _, email := range invalidEmails {
        if email = strings.TrimSpace(email); email != "" {
            if util.Str(email).IsEmail() {
                t.Errorf("Email %q should be invalid", email)
            }
        }
    }
}

🚀 持续集成测试

1. GitHub Actions 配置

# .github/workflows/test.yml
name: Tests

on:
  push:
    branches: [ main, develop ]
  pull_request:
    branches: [ main ]

jobs:
  test:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        go-version: [1.19, 1.20, 1.21]
    
    steps:
    - uses: actions/checkout@v3
    
    - name: Set up Go
      uses: actions/setup-go@v3
      with:
        go-version: ${{ matrix.go-version }}
    
    - name: Cache dependencies
      uses: actions/cache@v3
      with:
        path: ~/go/pkg/mod
        key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
        restore-keys: |
          ${{ runner.os }}-go-
    
    - name: Download dependencies
      run: go mod download
    
    - name: Run tests
      run: |
        go test -v -race -cover -coverprofile=coverage.out ./...
        go tool cover -func=coverage.out
    
    - name: Upload coverage
      uses: codecov/codecov-action@v3
      with:
        file: ./coverage.out
        flags: unittests
        name: codecov-umbrella
    
    - name: Run benchmarks
      run: go test -bench=. -benchmem ./...
    
    - name: Check code quality
      run: |
        go vet ./...
        go install honnef.co/go/tools/cmd/staticcheck@latest
        staticcheck ./...

2. 测试脚本

#!/bin/bash
# scripts/test-all.sh

set -e

echo "🧪 Running comprehensive test suite..."

# 基础测试
echo "📋 Running unit tests..."
go test -v -race ./...

# 覆盖率测试
echo "📊 Generating coverage report..."
go test -v -race -cover -coverprofile=coverage.out ./...
go tool cover -html=coverage.out -o coverage.html

# 性能测试
echo "⚡ Running benchmarks..."
go test -bench=. -benchmem -cpuprofile=cpu.prof -memprofile=mem.prof ./...

# 代码质量检查
echo "🔍 Running code quality checks..."
go vet ./...
golangci-lint run

# 安全检查
echo "🔒 Running security scan..."
gosec ./...

# 集成测试
echo "🔗 Running integration tests..."
go test -tags=integration -v ./...

# 压力测试
echo "💪 Running stress tests..."
go test -tags=stress -v ./...

echo "✅ All tests completed successfully!"

💬 获取帮助

如果您在测试编写中遇到问题:


🎯 良好的测试是高质量代码的保证,让我们一起构建可靠的 Go-Util!