How to conduct golang tests consistently?

When I run go test , my output is:

 --- FAIL: TestGETSearchSuccess (0.00s) Location: drivers_api_test.go:283 Error: Not equal: 200 (expected) != 204 (actual) --- FAIL: TestGETCOSearchSuccess (0.00s) Location: drivers_api_test.go:391 Error: Not equal: 200 (expected) != 204 (actual) 

But after I run go test again, all my tests will pass.

Tests only complete when I reset my mysql database, and then run go test for the first time.

For each GET request, I make a POST request earlier to make sure the data is created in the database.

Can someone help me in making sure the tests run sequentially? Are POST requests executed before GET requests?

+8
go testing
source share
3 answers

You cannot / should not rely on the test execution order. The order in which tests are performed is not defined, and using the test flags you can exclude the execution of tests, so you have no guarantee that they will work at all.

For example, the following command will run only those tests whose name contains the letter 'W' :

 go test -run W 

Also note that if some test functions indicate that they have the right to be executed in parallel using the T.Parallel() method, the go tool will change the order of the tests, first run non-parallel tests and then run parallel tests in parallel under certain circumstances (controlled by test flags such as -p ). You can see examples of this in this answer: Are tests run in parallel in Go or one by one?

Tests should be independent of each other. If the test function has prerequisites that cannot be executed / implemented in another test function.

Parameters for completing additional tasks before running the test function:

  • You can put it in the most test function
  • You can put it in the init() batch function in the _test.go file _test.go . This will be done once before running the test functions.
  • You can select the TestMain() function, which will be called first and in which you can perform additional settings before you call M.Run() to start the execution of the test functions.
  • You can mix the above parameters.

In your case, in the init() or TestMain() package, you should check if your database is initialized (test records are inserted), and if not, insert test records.

Please note that starting with Go 1.7, you can use subtests in which you determine the order in which subtests are executed. For more information, see the blog post: Using Subtests and Sub-Tests and Batch testing .

+18
source share

Besides third-party libraries such as Convey and Ginkgo , with simple Golang 1.7 you can run tests sequentially. You can read more here.

 func TestFoo(t *testing.T) { // <setup code> t.Run("A=1", func(t *testing.T) { ... }) t.Run("A=2", func(t *testing.T) { ... }) t.Run("B=1", func(t *testing.T) { ... }) // <tear-down code> } 

And you can run them conditionally with

 go test -run '' # Run all tests. go test -run Foo # Run top-level tests matching "Foo", such as "TestFooBar". go test -run Foo/A= # For top-level tests matching "Foo", run subtests matching "A=". go test -run /A=1 # For all top-level tests, run subtests matching "A=1". 

So let's say you have the user package from the REST api that you want to check. You need to test the create handler to be able to test the login handler. Normally I would have this on user_test.go

 type UserTests struct { Test *testing.T} func TestRunner(t *testing.T) { t.Run("A=create", func(t *testing.T) { test:= UserTests{Test: t} test.TestCreateRegularUser() test.TestCreateConfirmedUser() test.TestCreateMasterUser() test.TestCreateUserTwice() }) t.Run("A=login", func(t *testing.T) { test:= UserTests{Test: t} test.TestLoginRegularUser() test.TestLoginConfirmedUser() test.TestLoginMasterUser() }) } 

Then I can add methods to the UserTest type that will not be executed by the go test command in any _test.go file

 func (t *UserTests) TestCreateRegularUser() { registerRegularUser := util.TableTest{ Method: "POST", Path: "/iot/users", Status: http.StatusOK, Name: "registerRegularUser", Description: "register Regular User has to return 200", Body: SerializeUser(RegularUser), } response := util.SpinSingleTableTests(t.Test, registerRegularUser) util.LogIfVerbose(color.BgCyan, "IOT/USERS/TEST", response) } 
+5
source share

The best way to achieve this is to create the TestMain presented here .

 import ( "testing" "os" ) func TestMain(m *testing.M) { // Do your stuff here os.Exit(m.Run()) } 
+2
source share

All Articles