如何在并行化的 Go 测试中正确使用通道?

How do I properly use channels inside a parallelized Go test?

我正在尝试并行子测试,但遇到了 goroutine 死锁错误。假设 tt 是具有有效值的 table 测试,并且 LastIndex 是被测试的函数,以下代码运行所有测试,但出现错误:

for _, tt := range tests {
    tt := tt
    t.Run("foo", func(t *testing.T) {
        t.Parallel()
        done := make(chan bool)
        for {
            select {
            case <-done:
                return
            case <-time.After(time.Second):
                if got := LastIndex(tt.list, tt.x); got != tt.want {
                    t.Fatalf("LastIndex(%v, %v) = %v, want %v", tt.list, tt.x, got, tt.want)
                } else {
                    done <- true
                }
            }
        }
    })
}

具体来说:fatal error: all goroutines are asleep - deadlock!

这个错误意味着超级测试仍在等待这些子测试的结果,但 returnt.Fatalf() 不应该退出它们吗? Go 文档说通道不一定需要关闭,但我还是尝试关闭它们,但仍然没有用。我还尝试在子测试范围外、范围迭代内创建通道,并用 t.Cleanup() 延迟关闭它,但这也不起作用。

完整代码在这里:https://play.golang.org/p/1ujIIl7pjY9 并非所有测试都通过,这是故意的

我做错了什么?

t.Run 调用在单独的 goroutine 中运行测试函数并等待它 returns。如果测试成功,测试中的 for-loop 将写入 done 通道,但是没有其他 goroutines 从 done 通道读取,因此出现死锁。

您可以关闭它,而不是写入 done 频道。这将在下次检测到。但是请注意,您 运行 只有一个 goroutine,这里没有并发。