文章

Go 工程化与测试

Go 工程化与测试

一句话:Go 的工程化哲学是”约定优于配置”——go test 内建测试、golangci-lint 统一 lint、标准项目布局。本文补齐 Go 基础速查 没覆盖的工程与质量环节。

模块与版本管理

module github.com/myorg/myop

go 1.23

require (
    k8s.io/client-go v0.31.0
    sigs.k8s.io/controller-runtime v0.19.0
)
  • 语义版本:v0.x 不保证兼容,v1+ 才保证 API 稳定(影响你的 Operator 依赖选择)
  • replace(开发期):本地调试时用 replace example.com/foo => ../foo
  • workspace(多模块)go work init 管理 monorepo 下的多个 module
  • 依赖最小版本选择(MVS):Go 选”能满足所有约束的最低版本”,与 npm 的”最新”不同——更可预测

错误处理(Go 1.13+ 的坑与最佳实践)

实践说明
error wrappingfmt.Errorf("read config: %w", err) 包裹,保留链
errors.Is判断”根因是不是某哨兵错误”,无视包裹层
errors.As把错误转成特定类型取字段
哨兵错误var ErrNotFound = errors.New("not found"),用 Is 判断
自定义错误实现 Error() string,可带字段(如状态码)
不要忽略_ = doX() 吞错是隐患;至少 log 或显式处理
if err := doX(); err != nil {
    return fmt.Errorf("doX failed: %w", err)   // 向上裹,别丢上下文
}
// 调用方
if errors.Is(err, ErrNotFound) { /* 特殊处理 */ }

泛型(Go 1.18+):克制使用

泛型解决”为不同类型写相同逻辑”,但别滥用——Go 仍偏好具体类型 + interface。

func Min[T constraints.Ordered](a, b T) T {
    if a < b { return a }
    return b
}

适用:容器/算法(slice 工具、map 合并)、避免 interface{} + 类型断言的性能/安全损失。不适用:过早抽象(YAGNI)。

测试:table-driven + benchmark + fuzz

// 1. Table-driven:一个函数测多用例
func TestParse(t *testing.T) {
    tests := []struct{ in, want string }{
        {"a", "A"}, {"b", "B"},
    }
    for _, tt := range tests {
        if got := Parse(tt.in); got != tt.want {
            t.Errorf("Parse(%q)=%q want %q", tt.in, got, tt.want)
        }
    }
}

// 2. Benchmark
func BenchmarkParse(b *testing.B) {
    for i := 0; i < b.N; i++ { Parse("x") }
}

// 3. Fuzz(Go 1.18+):自动生成奇怪输入找崩溃
func FuzzParse(f *testing.F) {
    f.Add("seed")
    f.Fuzz(func(t *testing.T, s string) { Parse(s) })
}
  • testify:断言库(require.Equal 等),提升可读性
  • 覆盖率go test -cover,关键路径争取 > 70%
  • 集成测试:用 envtest(kubebuilder 提供,起真 API Server 测 Operator)——你 K8s Controller/Operator 开发 必备

项目布局

目录作用
cmd/可执行入口(main)
internal/私有代码(编译器保证不被外部 import)
pkg/可被外部 import 的公共库
api/ / apis/CRD 类型定义(Operator 用)
test/集成/e2e 测试

internal/ 是 Go 特有的”强制封装”——比文档约定更可靠,Operator 项目必用。

Lint:golangci-lint

统一风格 + 抓 bug(govet、errcheck、staticcheck)。配置进 CI(你 CI-CD 系列的 Go workflow 应跑它)。

关联知识

参考资源

  • Go Blog: “Error handling and Go” / “Generics tutorial”
  • golangci-lint 文档

学习时间

| 内容 | 日期 | 状态 | |------|------| ------| | Go 工程化与测试 | 2026-07-24 | 完成:模块版本、错误处理、泛型、三类测试、布局、lint |

状态

  • 模块与版本
  • 错误处理最佳实践
  • 泛型克制用法
  • table-driven/benchmark/fuzz
  • 项目布局 + lint