主题
08 · 测试与表格驱动
目标:每个导出逻辑至少一个测试;习惯 table-driven。
官方:testing· How to Write Go Code · Testing · Table-driven tests 相关博文习惯
1. 文件与命令
| 约定 | 说明 |
|---|---|
foo.go | 实现 |
foo_test.go | 同包测试(可访问未导出符号)或 package foo_test 黑盒 |
func TestXxx(t *testing.T) | 测试函数 |
go test ./... | 跑当前模块测试 |
go test -race ./... | 竞态检测 |
go test -cover ./... | 覆盖率 |
2. Table-driven(官方社区默认风格)
go
func TestPreview(t *testing.T) {
tests := []struct {
name string
in string
max int
want string
}{
{name: "short", in: "hi", max: 10, want: "hi"},
{name: "trim", in: "hello world", max: 5, want: "hello..."},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := Preview(tt.in, tt.max)
if got != tt.want {
t.Fatalf("got %q, want %q", got, tt.want)
}
})
}
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
好处:加用例只加一行;失败时子测试名清晰。见 https://go.dev/blog/subtests 。
3. HTTP Handler 怎么测
用 httptest + http.Handler:
go
req := httptest.NewRequest(http.MethodGet, "/health", nil)
rr := httptest.NewRecorder()
handler.ServeHTTP(rr, req)
if rr.Code != http.StatusOK {
t.Fatalf("code=%d", rr.Code)
}1
2
3
4
5
6
2
3
4
5
6
第 10 篇小项目应用这个模式,而不是只靠手工 curl。
4. Example 即文档
go
func ExamplePreview() {
fmt.Println(Preview("abcdef", 3))
// Output:
// abc...
}1
2
3
4
5
2
3
4
5
go test 会跑 Example;也出现在 pkg.go.dev。标准库大量使用——这是「官方文档优先」的延伸:读 Example 比读博文快。
5. 和 Jest 对照
| Jest | Go |
|---|---|
describe / it | t.Run 子测试 |
expect(x).toBe | if got != want { t.Fatalf }(或第三方断言,入门不必) |
| mock 狂魔 | 优先接口 + fake 实现 |
| 快照测试 | 少用;关键用明确 want |
6. AI 时代:测试是防幻觉护栏
流程建议:
- 你先写 表格用例(含边界)
- 再让 AI 实现函数
go test红灯 → 只允许 AI 改实现,不轻易改测试迁就
或 TDD 反向:AI 生成测试后,你逐条确认用例是否合理(防 AI 测错的「自我实现」)。
提示词:
text
为函数 F 生成 table-driven 测试,包含:空输入、超长、非法 UTF-8(如适用)。
使用标准 testing 包与 t.Run。不要引入 testify。1
2
2
7. 验收清单
- [ ] 至少一个包
go test通过 - [ ] 会写 table-driven +
t.Run - [ ] 会用 httptest 测一个 Handler
- [ ] 知道
-race/-cover
