【发布时间】:2017-11-03 15:31:31
【问题描述】:
我有一个带有单元测试的 Go 文件,其中一些使用公共变量。我正在测试的代码中使用了另一个全局变量。所有这些都可能导致问题。
在 Go 中,当我们执行位于同一文件中的测试时,它们是如何运行的?并行或下一个不会在前一个完成之前开始?
【问题讨论】:
标签: unit-testing testing go
我有一个带有单元测试的 Go 文件,其中一些使用公共变量。我正在测试的代码中使用了另一个全局变量。所有这些都可能导致问题。
在 Go 中,当我们执行位于同一文件中的测试时,它们是如何运行的?并行或下一个不会在前一个完成之前开始?
【问题讨论】:
标签: unit-testing testing go
测试起来真的很容易:
func Test1(t *testing.T) {
fmt.Println("Test1 start")
time.Sleep(time.Second * 2)
fmt.Println("Test1 end")
}
func Test2(t *testing.T) {
fmt.Println("Test2 start")
time.Sleep(time.Second * 2)
fmt.Println("Test2 end")
}
func Test3(t *testing.T) {
fmt.Println("Test3 start")
time.Sleep(time.Second * 2)
fmt.Println("Test3 end")
}
使用go test 运行它,输出显示它是连续的:
Test1 start
Test1 end
Test2 start
Test2 end
Test3 start
Test3 end
所以正常的测试一个接一个地执行,但不要忘记没有定义顺序:How to run golang tests sequentially?
另请注意,测试函数可以将自己标记为可以并行执行,与使用T.Parallel() 方法的其他测试并行执行:
并行表示此测试将与(并且仅与)其他并行测试并行运行。
那么如果我们将上面的测试代码修改为:
func Test1(t *testing.T) {
t.Parallel()
fmt.Println("Test1 start")
time.Sleep(time.Second * 2)
fmt.Println("Test1 end")
}
func Test2(t *testing.T) {
t.Parallel()
fmt.Println("Test2 start")
time.Sleep(time.Second * 2)
fmt.Println("Test2 end")
}
func Test3(t *testing.T) {
fmt.Println("Test3 start")
time.Sleep(time.Second * 2)
fmt.Println("Test3 end")
}
用go test再次运行,输出为:
Test3 start
Test3 end
Test1 start
Test2 start
Test2 end
Test1 end
这证明了什么?测试的顺序没有定义,这次先执行Test3。然后Test1 和Test2 运行并行。
有一些测试标志控制并行执行。例如,-parallel 标志指定其中有多少可以并行运行。如果你用go test -parallel=1执行它,输出将再次变成连续的,但顺序将是Test3,Test1,Test2。
还要注意Go 1.7 introduced subtests and subbenchmarks。您可以在博文Using Subtests and Sub-benchmarks 中阅读更多相关信息:
在 Go 1.7 中,
testing包在 T 和 B 类型上引入了一个 Run 方法,允许创建子测试和子基准。子测试和子基准测试的引入可以更好地处理故障、细粒度地控制从命令行运行哪些测试、控制并行性,并且通常会产生更简单和更易于维护的代码。
子测试和子基准测试可以并行运行,并且有许多标志可以控制它们的执行,例如-parallel、-p、-cpu。运行 go help testflag 以查看完整的测试标志列表。
【讨论】:
默认情况下,一个包内的所有测试都是按顺序运行的。
此外,默认情况下,所有测试集都是并行运行的。
如果您使用默认值并且拥有针对通用持久层(如 rdbms)进行测试的不同包,这可能会导致问题。如果您对这种情况有疑问,那么运行 go test ./... -p 1 将阻止不同的测试套件同时运行。