Go中测试结构体方法需构造实例、调用方法、检查返回值或状态变更;使用testing包编写独立TestXxx函数,区分输入/动作/断言,支持表格驱动与接口模拟。

在 Go 中测试结构体方法,核心是通过构造实例、调用方法、检查返回值或状态变更,来验证对象行为是否符合设计预期。Go 原生的 testing 包足够轻量高效,无需额外框架即可完成高质量单元测试。
为结构体方法编写独立、可重复的测试函数
每个测试函数应聚焦单一行为,使用 TestXxx 命名(首字母大写),接收 *testing.T 参数。避免依赖外部状态或全局变量,确保每次运行结果一致。
- 用字面量或简单构造函数创建被测结构体实例
- 明确区分“输入”(调用前设置)、“动作”(方法调用)、“断言”(检查输出或副作用)
- 例如:测试一个
User.IncreaseAge()方法时,先设初始年龄为 25,调用后检查是否变为 26
验证方法的返回值与副作用需分开处理
Go 方法可能只返回值(如 String() string),也可能修改接收者(指针方法),或两者兼有。测试时要分别覆盖:
- 返回值:直接比较期望值,用
if got != want { t.Errorf(...) } - 状态变更:重新读取字段或调用 getter 方法确认内部变化
- 注意:值接收者方法无法修改原实例,必须用指针接收者才能改变状态
使用表格驱动测试提升覆盖率和可维护性
对同一方法的多种输入组合,推荐用切片定义测试用例,循环执行。清晰展示“输入-期望”映射,便于新增场景和定位失败原因。
立即学习“go语言免费学习笔记(深入)”;
示例结构:
tests := []struct {
name string
input int
wantErr bool
wantAge int
}{
{"zero years", 0, false, 25},
{"one year", 1, false, 26},
{"negative", -1, true, 25},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
u := &User{Age: 25}
err := u.AdjustAge(tt.input)
if (err != nil) != tt.wantErr {
t.Fatalf("AdjustAge() error = %v, wantErr %v", err, tt.wantErr)
}
if u.Age != tt.wantAge {
t.Errorf("Age = %d, want %d", u.Age, tt.wantAge)
}
})
}
模拟依赖时优先使用接口而非真实实现
若结构体方法依赖外部服务(如数据库、HTTP 客户端),将依赖抽象为接口,在测试中传入内存实现或桩(stub)。不建议直接 mock 结构体本身——Go 鼓励组合与接口,而非继承与重写。
- 定义
type DataStore interface { Save(data interface{}) error } - 结构体持有一个该接口字段:
ds DataStore - 测试时传入一个满足接口的匿名结构体或专用测试类型










