
Go 测试默认是串行还是并行?
Go 的 testing.T 默认所有测试函数是**串行执行**的,但同一个 TestXxx 函数内部调用 t.Parallel() 后,会被调度为并发运行——注意:这是“测试函数间串行、函数内可并行”,不是全局并行。
常见误解是以为加了 t.Parallel() 就能让所有测试一起跑,其实它只影响当前测试函数与其它标记了 t.Parallel() 的测试函数之间的调度关系。没加的仍会阻塞后续所有测试(包括并行组)。
- 没调用
t.Parallel()的测试:独占一个 goroutine,顺序执行,阻塞后续所有测试 - 调用了
t.Parallel()的测试:进入并行池,由 testing 主循环统一调度,并发数受-p参数或GOMAXPROCS限制 - 同一包内混合使用时,并行测试必须等所有前置非并行测试跑完才开始
如何强制控制多个 TestXxx 的执行顺序?
Go 原生不支持声明式测试顺序(比如 @Order 注解),go test 按源码中函数定义顺序执行 TestXxx,但这个顺序不可靠:依赖编译器解析顺序,且 go test ./... -run=Test* 可能跨包打乱。
真正可控的方式只有两种:合并逻辑进单个测试函数,或用命名前缀+字典序 trick(不推荐)。前者更直接:
立即学习“go语言免费学习笔记(深入)”;
- 把有依赖的测试逻辑写进一个
func TestSetupThenUse(t *testing.T),内部用子测试t.Run()拆分步骤 - 子测试之间天然顺序执行,且可单独运行(
go test -run="TestSetupThenUse/step2") - 避免在不同顶层测试函数间共享状态(如全局变量、文件、DB 连接),否则顺序一变就失败
示例:
func TestAuthFlow(t *testing.T) {
t.Run("setup_user", func(t *testing.T) { /* 创建用户 */ })
t.Run("login", func(t *testing.T) { /* 登录获取 token */ })
t.Run("access_protected", func(t *testing.T) { /* 用 token 请求 */ })
}
t.Parallel() 为什么有时没效果甚至变慢?
加了 t.Parallel() 却没提速,甚至 panic 或数据竞争,通常是因为没清理共享资源或误判了瓶颈类型。
- IO 密集型测试(如 HTTP 请求、文件读写)并行后可能触发系统句柄耗尽或服务限流,反而更慢
- 内存/计算密集型测试并行太多会加剧 GC 压力,尤其小对象高频分配场景
- 测试里用了全局变量、临时文件路径、端口号硬编码,多个并行实例会冲突(典型错误信息:
listen tcp :8080: bind: address already in use) - 忘记在并行测试中用
t.Cleanup()释放资源,导致后续测试被污染
建议:先用 go test -cpu=1,2,4 -bench=. 对比基准,再决定是否并行;对集成类测试,默认不加 t.Parallel() 更稳妥。
跨包或 Benchmark 里怎么协调执行节奏?
标准 testing 包不提供跨测试函数的同步原语,sync.WaitGroup 或 chan 在不同 TestXxx 间无效——每个测试函数运行在独立生命周期里,结束即销毁所有 goroutine。
- Benchmark 函数完全不支持
t.Parallel(),它的并发由b.N和b.RunParallel控制,和测试无关 - 需要跨测试共享状态?说明设计有问题——测试应尽量无状态、可重入;真要复用 setup,用
TestMain+ 全局变量(需加锁)或临时目录隔离 - 想等某个后台服务启动完成再测?别在测试里轮询,改用
net.DialTimeout等连接就绪,或用testify/suite类库封装生命周期
最常被忽略的一点:并行测试里打印日志用 t.Log() 而不是 fmt.Println(),否则输出时间戳错乱、无法关联到具体测试实例。










