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 <dir> -type d -exec go test {} \;
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.)
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.
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="^(Test|Benchmark)[^_](.*)"
- For integration tests
go test -run"^(Test|Benchmark)_(.*)"
- Run both using the normal
go test