Go test your tests in Go with go test
Today, we are going to talk about something that is boring… but necessary; tests.
But you are probably tired of reading blog posts that talk about “Why testing is important”, “Why your thing should have tests”, and “Top 5 reasons you should adopt test-driven development”. So, instead of writing about the usual “You need tests because it will blah your blah with blah because of blah”, I want to talk about something else; how to make writing tests not suck as much.
Here are some tips and tricks I picked up while writing tests for fac.
1. Current Testing Directory
Here is a fun fact; when you run go test
for a package, the test binary will be run within the package being tested.
Allow me to demonstrate. Assume your project directory is setup like this
project
└── server
├── server.go
└── server_test.go
And your server_test.go
looks like this
package server
import (
"os"
"testing"
)
func TestCoolServerStuff(t *testing.T) {
wd, _ := os.Getwd()
t.Log(wd)
}
If you run this from your root project
directory, you will get the following output
➜ pwd
/Users/mikechoi/src/go/src/github.com/mkchoi212/project
➜ go test -v
=== RUN TestCoolServerStuff
--- PASS: TestCoolServerStuff (0.00s)
server_test.go:10: github.com/mkchoi212/project/server
PASS
ok github.com/mkchoi212/project/server 0.007s
Notice that the log says github.com/mkchoi212/project/server
and not whatever pwd
said.
2. testdata is ignored
According to this Go documentation,
Directory and file names that begin with “.” or “_” are ignored by the go tool, as are directories named “testdata”.
So, if you need mock files to test something - such as response.json
for your networking functions - you can place it in package_directory/testdata/response.json
. Now, you can easily load the mock files like so
func TestServerResponse(t *testing.T) {
if json, err := os.Open("testdata/response.json"); err != nil {
doStuffWithNetworkResponse(json)
t.Log("🎉")
}
}
Notice that we are able to simple say testdata/response.json
because of #1.
3. testhelper
This is a simple concept but is very helpful when writing tests in Go. When writing code in Go, you probably have written thousands of lines of code that look like this
if data, err := doSomethingCool(); err != nil {
doMoreCoolThingsHere(data)
}
The trouble is that this is what 80% of statements you are going to tests are going to look like. After all, you are testing if something either didn’t return an error, is equal to something, and or didn’t crap out. Eventually, your testsuite will get filled with if data, err := ....; err != nil
statements. So, the brilliant solution to this is to make helper functions.
Instead of writing the code you saw previously with bunch of if-statements, you can now write the following.
func TestCoolThing(t *testing.T) {
data, err := doSomethingCool()
// Awesome
testhelper.Ok(t, err)
otherData, err := doSomethingAmazing()
testhelper.Ok(t, err)
// This is really useful as well
testhelper.Equals(t, data, otherData)
}
And if a test fails for some reason, the helper functions will print out the error messages in red and pin-point the location where the test failed.
3. go test tricks
Here are some additional tips and tricks you can use while using go test
.
Test all packages in project directory
./...
is the magic argument.
➜ go test
ok github.com/mkchoi212/project [no test files]
➜ go test ./...
ok github.com/mkchoi212/project [no test files]
ok github.com/mkchoi212/project/server 0.012s
ok github.com/mkchoi212/project/testhelper [no test files]
Ignore package while testing
You might need this when you don’t necessarily need to test something or because you just want a higher code coverage percentage 😄
Notice
testhelper
is not being tested any more
➜ go test `go list ./... | grep -v 'testhelper'`
ok github.com/mkchoi212/project [no test files]
ok github.com/mkchoi212/project/server 0.012s
Code coverage statistics
➜ go test --cover
PASS
coverage: 100.0% of statements
ok github.com/mkchoi212/project/server 0.011s
« Common Gotchas in Go
Open-source self-diagnostics »