包测试的串行执行

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

Serial execution of package tests

问题

我为一个Web API实现了几个包,每个包都有自己的测试用例。当使用go test ./api/pkgname测试每个包时,测试通过。但是,如果我想一次性运行所有测试用例,使用go test ./api/...,测试用例总是失败。

在每个测试用例中,我使用DROP SCHEMA public CASCADECREATE SCHEMA public重新创建整个模式,并应用所有迁移。测试套件会随机报告错误,说一个关系/表不存在,所以我猜每个测试套件(每个包)都以某种方式并行运行,从而搞乱了数据库状态。

我尝试传递一些测试标志,如go test -cpu 1 -parallel 0 ./src/api/...,但没有成功。

问题可能是测试并行运行吗?如果是的话,我如何强制串行执行?

更新:

目前,我使用以下解决方法来运行测试,但我仍然想知道是否有更好的解决方案

find <dir> -type d -exec go test {} \;
英文:

I have implemented several packages for a web API, each with their own test cases. When each package is tested using go test ./api/pkgname the tests pass. If I want to run all tests at once with go test ./api/... test cases always fail.

In each test case, I recreate the entire schema using DROP SCHEMA public CASCADE followed by CREATE SCHEMA public and apply all migrations. The test suite reports errors back at random, saying a relation/table does not exist, so I guess each test suite (per package) is run in parallel somehow, thus messing up the DB state.

I tried to pass along some test flags like go test -cpu 1 -parallel 0 ./src/api/... with no success.

Could the problem here be tests running in parallel, and if yes, how can I force serial execution?

Update:

Currently I use this workaround to run the tests, but I still wonder if there's a better solution

find &lt;dir&gt; -type d -exec go test {} \;

答案1

得分: 37

正如其他人指出的那样,-parallel不能完成这个任务(它只在包内起作用)。然而,你可以使用-p=1标志来按顺序运行包测试。这在这里有文档记录:

http://golang.org/src/cmd/go/testflag.go

但是(据我所知)在命令行、go help等地方没有提到。我不确定它是否打算保留下来(尽管我认为如果它被移除了,应该修复-parallel)。

英文:

As others have pointed out, -parallel doesn't do the job (it only works within packages). However, you can use the flag -p=1 to run through the package tests in series. This is documented here:

http://golang.org/src/cmd/go/testflag.go

but (afaict) not on the command line, go help, etc. I'm not sure it is meant to stick around (although I'd argue that if it is removed, -parallel should be fixed.)

答案2

得分: 9

go工具是为了更方便地运行单元测试而提供的,它假设*_test.go文件中包含单元测试。因为它假设它们是单元测试,所以也假设它们是隔离的。听起来你的测试要么不是单元测试,要么是单元测试但违反了单元测试应该满足的假设。

如果你的意思是这些测试应该是单元测试,那么你可能需要为你的单元测试创建一个模拟数据库。一个模拟数据库,最好是内存中的,可以确保单元测试是隔离的,不会被其他单元测试干扰。

如果你的意思是这些测试应该是集成测试,那么最好不要使用go工具进行这些测试。你可能想要创建一个单独的测试二进制文件,可以控制其运行,并在其中编写集成测试脚本。

好消息是,在Go语言中创建一个模拟对象非常容易。将你的代码更改为接受一个包含你关心的数据库方法的接口,然后为测试目的编写一个内存中的接口实现,并将其传递给你想要测试的应用代码。

英文:

The go tool is provided to make running unit tests easier using the convention that *_test.go files contain unittests in them. Because it assumes they are unittests it also assumes they are hermetic. It sounds like your tests either aren't unittests or they are but violate the assumptions that a unittest should fulfill.

In the case that you mean for these tests to be unittests then you probably need a mock database for your unittests. A mock, preferrably in memory, of your database will ensure that the unittest is hermetic and can't be interfered with by other unittests.

In the case that you mean for these tests to be integration tests you are probably better off not using the go tool for these tests. What you probably want is to create a seperate test binary whose running you can control and write you integration test scripts in there.

The good news is that creating a mock in Go is insanely easy. Change your code to take an interface with the methods you care about for the databases and then write an in memory implementation of that interface for testing purposes and pass it into your application code that you want to test.

答案3

得分: 3

只是为了澄清,@Jeremy的答案仍然是被接受的:

由于我的集成测试只在一个包(api)上运行,最后我移除了单独的测试二进制文件,并创建了一个模式来区分测试类型:

  • 单元测试使用正常的TestX命名
  • 集成测试使用Test_X命名

我创建了shell脚本(utest.sh/itest.sh)来运行其中之一。

  • 对于单元测试,使用命令go test -run="^(Test|Benchmark)[^_](.*)"
  • 对于集成测试,使用命令go test -run"^(Test|Benchmark)_(.*)"
  • 使用正常的go test命令同时运行两者。
英文:

Just to clarify, @Jeremy's answer is still the accepted one:

Since my integration tests were only run on one package (api), I removed the separate test binary in the end and created a pattern to separate test types by:

  • Unit tests use the normal TestX name
  • Integration tests use Test_X

I created shell scripts (utest.sh/itest.sh) to run either of those.

  • For unit tests go test -run=&quot;^(Test|Benchmark)[^_](.*)&quot;
  • For integration tests go test -run&quot;^(Test|Benchmark)_(.*)&quot;
  • Run both using the normal go test

huangapple
  • 本文由 发表于 2013年3月31日 01:15:26
  • 转载请务必保留本文链接:https://go.coder-hub.com/15721238.html
匿名

发表评论

匿名网友

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

确定