在Go语言中,测试是并行执行还是逐个执行的?

huangapple go评论75阅读模式
英文:

Are tests executed in parallel in Go or one by one?

问题

我有一个带有单元测试的Go文件,其中一些测试使用了一个公共变量。另一个全局变量在我正在测试的代码中使用。所有这些都可能引起问题。

在Go中,当我们执行位于同一文件中的测试时,它们是如何运行的?是并行运行还是下一个测试在前一个测试完成之前不会开始?

英文:

I have a Go file with unit tests and some of them use a common variable. Another global variable is used in the code that I'm testing. All of this can cause a problem.

In Go when we execute tests that are located in the same file how does they run? In parallel or next one will not start before previous one is finished ?

答案1

得分: 19

默认情况下,一个包中的所有测试是按顺序运行的。

同样,默认情况下,所有测试集合是并行运行的。

如果您使用默认设置,并且有不同的包对共享的持久层(如关系型数据库)进行测试,可能会出现问题。如果您在这种情况下遇到问题,那么运行go test ./... -p 1将阻止不同的测试套件并发运行。

英文:

By default, all the tests within a package are run sequentially.

Also by default, all of the sets of tests are run in parallel.

This may cause issues if you use defaults and have different packages that test against a common persistence layer (like a rdbms). If you have issues with this case, then running go test ./... -p 1 will prevent different test suites from running concurrently.

答案2

得分: 16

这是一个很容易测试的例子:

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

所以普通的测试是依次顺序执行的,但不要忘记顺序是不确定的:https://stackoverflow.com/questions/31201858/how-to-run-golang-tests-sequentially/31204016#31204016

还要注意,测试函数可以使用T.Parallel()方法标记自己适合并行执行,与其他也使用相同方法的测试一起并行执行:

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,然后Test1Test2并行运行。

有一些测试标志可以控制并行执行。例如,-parallel标志指定可以并行运行的测试数量。如果使用go test -parallel=1执行,输出将再次变为顺序执行,但顺序将是Test3Test1Test2

还要注意,Go 1.7引入了子测试和子基准测试。您可以在博客文章Using Subtests and Sub-benchmarks中了解更多信息:

在Go 1.7中,testing包在TB类型上引入了一个Run方法,允许创建子测试和子基准测试。引入子测试和子基准测试可以更好地处理失败,从命令行细粒度控制要运行的测试,控制并行性,并且通常会导致更简单和更易维护的代码。

子测试和子基准测试可以并行运行,并且有许多标志可以控制它们的执行,例如-parallel-p-cpu。运行go help testflag以查看完整的测试标志列表。

英文:

It's really easy to test it:

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")
}

Running it with go test, the output shows it's sequential:

Test1 start
Test1 end
Test2 start
Test2 end
Test3 start
Test3 end

So normal tests are executed one after the other, sequentially, but don't forget that order is not defined: https://stackoverflow.com/questions/31201858/how-to-run-golang-tests-sequentially/31204016#31204016

Also note that a test function can mark itself eligible for parallel execution, paralell with other tests that also do the same using the T.Parallel() method:

> Parallel signals that this test is to be run in parallel with (and only with) other parallel tests.

So if we modify the above testing code to:

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")
}

Running it again with go test, the output is:

Test3 start
Test3 end
Test1 start
Test2 start
Test2 end
Test1 end

What does this prove? The order of tests is not defined, Test3 was executed first this time. And then Test1 and Test2 were run parallel.

There are some testing flags that control parallel execution. For example the -parallel flag specifies how many of these may run parallel. If you execute it with go test -parallel=1, the output will again become sequential, but the order will be Test3, Test1, Test2.

Also note that Go 1.7 introduced subtests and subbenchmarks. You can read more about this in blog post Using Subtests and Sub-benchmarks:

> In Go 1.7, the testing package introduces a Run method on the T and B types that allows for the creation of subtests and sub-benchmarks. The introduction of subtests and sub-benchmarks enables better handling of failures, fine-grained control of which tests to run from the command line, control of parallelism, and often results in simpler and more maintainable code.

Subtests and subbenchmarks may run parallel, and there are a number of flags that may control their execution, e.g. -parallel, -p, -cpu. Run go help testflag to see the complete list of testing flags.

huangapple
  • 本文由 发表于 2017年6月2日 17:19:21
  • 转载请务必保留本文链接:https://go.coder-hub.com/44325232.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定