【问题标题】:How do I properly use channels inside a parallelized Go test?如何在并行化 Go 测试中正确使用通道?
【发布时间】:2021-02-15 15:47:26
【问题描述】:

我正在尝试并行子测试,但遇到了 goroutine 死锁错误。假设tt 是一个具有有效值的表测试,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 并非所有测试都通过,这是故意的

我做错了什么?

【问题讨论】:

    标签: unit-testing go testing parallel-processing channel


    【解决方案1】:

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

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

    【讨论】:

    • 是的,编辑了问题以添加缺少的 t.Parallel() 每次运行调用。用关闭的工作替换发送。
    猜你喜欢
    • 2014-10-11
    • 1970-01-01
    • 2018-09-02
    • 2017-12-30
    • 1970-01-01
    • 1970-01-01
    • 2013-11-28
    • 1970-01-01
    • 2014-06-05
    相关资源
    最近更新 更多