【发布时间】:2021-12-30 22:10:51
【问题描述】:
假设我有一个函数,如果它作为 go 例程异步执行:
func f(wg *sync.WaitGroup){
defer wg.Done()
// Do sth
}
main(){
var wg sync.WaitGroup
wg.Add(1)
go f(&wg)
wg.Wait() // Wait until f is done
// ...
}
如何为f 创建一个单元测试以确保调用wg.Done()?
一种选择是在调用f 之后直接在测试中调用wg.Done()。如果f 调用wg.Done() 失败,测试将出现恐慌,这并不好。
另一种选择是为sync.WaitGroup 创建一个接口,但这似乎有点奇怪。
【问题讨论】:
-
事实上,1.18 似乎确实从 1.17 改变了 WaitGroup 的结构,所以如果你确实使用上面的建议,然后在 2021 年初升级到 1.18...他们的测试是有保证的去炸掉。 1.17 和 current master
-
如果 Done 没有被调用,那么 Wait 不会返回并且测试会被破坏。您不需要检查 WaitGroup 的内部结构。
-
因为这就是您测试此代码的方式。在单元测试中使用 goroutine 并没有错,它正在测试作为 goroutine 的代码。并发是语言使用的基础,而不是仅用于集成的东西。
-
@RasmusN 你是在这里向后弯腰的人——首先要避免在测试中使用 goroutines(可能是因为你在其他语言中的并发经验让你认为它是要远离的东西单元测试),然后与 JimB 争论,而不是从他们的贡献中学习。放手去吧。让 JimB 这样有经验的人指导您。
-
除非您解决了停机问题,否则您无法证明任何一组测试都会完成。为什么你计划让测试经常失败?我们总是在函数开始时精确地推迟 Done,因此它永远不会被跳过,并且在审查时将其删除是显而易见的。如果您以某种方式跳过它,则测试会超时一次,然后您就可以修复它。
标签: unit-testing go synchronization waitgroup