Go: how to run tests for multiple packages?

社会主义新天地 提交于 2019-11-30 08:53:42

Update: As pointed out by @Gal Ben-Haim, adding the (undocumented) go test -p 1 flag builds and tests all packages in serial. As put by the testflag usage message in the Go source code:

-p=n: build and test up to n packages in parallel

Old answer:

When running go test ./..., the tests of the different packages are in fact run in parallel, even if you set parallel=1 (only tests within a specific package are guaranteed to be run one at a time). If it is important that the packages be tested in sequence, like when there is database setup/teardown involved, it seems like the only way right now is to use the shell to emulate the behavior of go test ./..., and forcing the packages to be tested one by one.

Something like this, for example, works in Bash:

find . -name '*.go' -printf '%h\n' | sort -u | xargs -n1 -P1 go test

The command first lists all the subdirectories containing *.go files. Then it uses sort -u to list each subdirectory only once (removing duplicates). Finally all the subdirectories containing go files get fed to go test via xargs. The -P1 indicates that at most one command is to be run at a time.

Unfortunately, this is a lot uglier than just running go test ./..., but it might be acceptable if it is put into a shell script or aliased into a function that's more memorable:

function gotest(){   find $1 -name '*.go' -printf '%h\n' | sort -u | xargs -n1 -P1 go test; }

Now all tests can be run in the current directory by calling:

gotest .

apparently running go test -p 1 runs everything sequentially (including build), I haven't see this argument in go help test or go help testflag

I am assuming that because the packages individually pass that in this situation you are also dropping the DB before that test as well.

Therefore it sounds like the state of the DB for each package test is expected to be empty.
So between each set of the package tests the DB must be emptied. There are two ways around this, not knowing your entire situation I will briefly explain both options:

Option 1. Test Setup

Add an init() function to the start of each package _test file which you then put processing to remove the DB. This will be run before the init() method of the actual package:

func init() {
    fmt.Println("INIT TEST")
    // My test state initialization
    // Remove database contents
}

Assuming that the package also had a similar print line you would see in the output (note the stdout output is only displayed when the a test fails or you supply the -v option)

INIT TEST
INIT PACKAGE

Option 2. Mock the database

Create a mock for the database (unless that is specifically what you are testing). The mock db can always act like the DB is blank for the starting state of each test.

Please try out the following github repository.

https://github.com/appleboy/golang-testing

Copy coverage.sh to /usr/local/bin/coverage and change permission.

$ curl -fsSL https://raw.githubusercontent.com/appleboy/golang-testing/master/coverage.sh /usr/local/bin/coverage
$ chmod +x /usr/local/bin/coverage
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!