如何为 f 创建一个单元测试以确保调用 wg.Done()?
像这样的东西:
func TestF(t *testing.T) {
wg := &sync.WaitGroup{}
wg.Add(1)
// run the task asynchronously
go f(wg)
// wait for the WaitGroup to be done, or timeout
select {
case <-wrapWait(wg):
// all good
case <-time.NewTimer(500 * time.Millisecond).C:
t.Fail()
}
}
// helper function to allow using WaitGroup in a select
func wrapWait(wg *sync.WaitGroup) <-chan struct{} {
out := make(chan struct{})
go func() {
wg.Wait()
out <- struct{}{}
}()
return out
}
您不直接检查 WaitGroup ,无论如何您都不能这样做。相反,在给定预期输入的情况下,您断言该函数的行为符合预期。
在这种情况下,预期的输入是 WaitGroup 参数,预期的行为是wg.Done()
最终被调用。这在实践中意味着什么?这意味着如果函数成功,计数为 1 的 WaitGroup 将达到 0 并允许wg.Wait()
继续。
defer wg.Done()
开头的声明f
已经确保测试对错误或崩溃具有弹性。添加超时只是为了确保测试将在合理的时间内完成,即它不会让您的测试套件停顿太久。就个人而言,我更喜欢使用明确的超时,无论是使用计时器还是使用上下文,1)如果有人忘记在 CI 级别设置超时,可以避免出现问题,2)让任何签出 repo 并运行测试套件的人都可以使用时间上限,即避免依赖 IDE 配置或诸如此类的东西。