微服务tdd必须从testxxx函数开始定义契约,遵循文件名xxx_test.go、函数名testxxx、签名func testxxx(t *testing.t)三规则;http测试用httptest.newrecorder拦截响应;依赖通过接口注入实现隔离;每次新增功能前须手动验证“红阶段”失败。

微服务不是先写 handler 再补测试,而是从 TestXxx 函数开始定义服务契约——没测通的接口,不许暴露给其他服务。
go test 找不到你的测试函数?检查三个硬性命名规则
Go 的测试发现机制非常机械,不识别就是不识别,不会报错提示你哪里错了。
- 文件名必须是
xxx_test.go(不能是test_xxx.go或xxx_test.go.bak) - 函数名必须是
TestXxx(首字母大写,Xxx是任意驼峰名,不能是testXxx或TESTXXX) - 函数签名必须是
func TestAdd(t *testing.T)(参数类型不能写成*testing.TB或漏掉t)
常见现象:运行 go test -v 输出 no tests to run,但你明明写了 func testHandler(t *testing.T)——它被完全忽略,连失败都不会有。
HTTP handler 测试卡在 “红阶段” 过不去?用 httptest.NewRecorder 拦截响应
微服务里最常写的 http.HandlerFunc 依赖 http.ResponseWriter 和 *http.Request,直接调用没法断言状态码或 body。别 mock net/http,用标准库给的工具。
- 用
httptest.NewRecorder()替代真实响应器,它能捕获写入的 status、header、body - 构造请求用
httptest.NewRequest("GET", "/api/v1/tasks", nil),不用手拼&http.Request{...} - 测试失败时,
t.Errorf("status=%d, want %d; body=%s", w.Code, http.StatusOK, w.Body.String())能立刻看到差异
示例片段:
Go 配置库,使用 spf13/viper — 分层优先级(flag > env >file > KV > default),提供 BindPFlag/BindPFlags、SetEnvPrefix + SetEnvKeyReplace 等功能。
func TestListTasksHandler(t *testing.T) {
w := httptest.NewRecorder()
r := httptest.NewRequest("GET", "/api/v1/tasks", nil)
ListTasksHandler(w, r) // 假设这是你的 handler
if w.Code != http.StatusOK {
t.Errorf("expected status %d, got %d", http.StatusOK, w.Code)
}
}
重构时外部依赖(DB/Redis)让测试变慢又不稳定?抽接口 + 传参注入
微服务测试跑得慢,90% 是因为没隔离外部调用。不要在测试里起真实数据库,也不要写 if os.Getenv("TEST") == "true" 这种分支。
- 把 DB 操作封装进接口,比如
type TaskStore interface { List() ([]Task, error) } - handler 函数接收该接口为参数:
func ListTasksHandler(store TaskStore) http.HandlerFunc - 测试时传入内存实现:
store := &mockTaskStore{tasks: []Task{{ID: 1, Title: "test"}}} - 注意:接口方法名必须首字母大写(
List),否则测试文件无法实现它
这样做的好处是:单测不依赖网络、不依赖 Docker、不依赖初始化脚本,go test -short 可以秒级跑完。
覆盖率高 ≠ TDD 做对了:红-绿-重构循环必须手动验证“红”
很多人跑通 go test -cover 就以为 TDD 完成了,但漏掉了最关键的一步:确认测试真能失败。
- 在写完
TestListTasksHandler后,先删掉 handler 实现,或让它panic("not implemented"),再跑go test -v—— 必须看到FAIL和明确错误输出 - 如果测试“一直绿”,说明它根本没覆盖逻辑路径(比如你忘了调 handler,或断言写成了
t.Log) - 微服务里最容易被绕过的“红阶段”是中间件和错误路径:400/404/500 场景必须显式构造并验证
真正的 TDD 不是“有测试”,而是每次新增功能前,都亲手把测试推到红区——那才是契约成立的起点。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










