如何在Go单元测试中校验sync.WaitGroup.Done()是否被正常调用
测试方案
推荐方案:带超时的非阻塞等待测试(无代码侵入)
这个方案不需要修改原有业务代码,也不需要做接口适配,更不会出现panic问题,实现逻辑非常简单:给WaitGroup的等待操作加超时阈值,wg.Done()如果正常调用,等待会立刻结束,超过阈值则判定测试失败。
测试代码示例:
import ( "sync" "testing" "time" ) func TestF_WgDoneIsCalled(t *testing.T) { var wg sync.WaitGroup wg.Add(1) // 若f内部无其他异步逻辑,可直接同步调用f(&wg),不需要开goroutine go f(&wg) // 接收等待完成信号 waitDone := make(chan struct{}, 1) go func() { wg.Wait() waitDone <- struct{}{} }() // 超时阈值可根据f的实际执行时长调整,单元测试一般设1秒完全足够 select { case <-waitDone: // 正常返回,说明wg.Done()被正常调用 case <-time.After(1 * time.Second): t.Fatal("f函数未正常执行wg.Done()") } }
方案优势
- 完全不侵入生产代码,不需要修改原函数的参数定义和实现逻辑
- 不会出现panic问题,超时后只会标记测试失败,不会影响其他测试用例执行
- 逻辑简单易懂,不需要额外的依赖和适配代码
如果你的测试场景完全不能接受超时判定,也可以选择对WaitGroup做极简的测试封装,仅在测试代码中继承sync.WaitGroup新增计数器统计Done的调用次数,不需要修改生产代码的参数类型,仅在测试时用子类实例传入即可,实现难度远低于完整的接口适配。
内容的提问来源于stack exchange,提问作者RasmusN
相关产品推荐
相关产品推荐

