Testing in Go - udaybhanu007/OVN-Poc GitHub Wiki
1) Introduction to Testing in Go
- Full featured testing and profiling tools
- Complete API for test execution (like maven in other languages)
- Little support for assertions
Test related packages in Go
- testing - home for working with testing
- testing/quick - specified for blackbox testing
- testing/iotest - very specific to reader/writers from an external source
- net/http/httptest - network applications like network I/O, including TCP/IP, UDP
Testing libraries outside Go
- testify - has good assertion experience
- Ginkgo - behavioral driven testing
- GoConvey - browser based format than in command line
4. httpexpect - end to end webservices testing, popular for testing rest api
5. gomock - mock your go objects
- go-sqlmock - testing with sql mock .
2) Creating and running tests
Naming Conventions
- add _test to the file names egs : main_test.go (this does 2 things for us 1. it will get identified by the build tool for testing 2. when creating production builds these files will get excluded from the binaries that are created)
- all the functions intended for testing should be prefixed with Test egs : TestFoo
- accept one parameter to the test function which is a pointer to testing.T object egs: TestFoo(t *testing.T) (this is to use this object later in the function for example if a failure is reported and hence get access to the test runner)
- you can have the test files in the same package as the source code, which will help you do whitebox testing
- you can keep all the tests related to a particular package in another package but with a package name _test egs : say your source code is in a package with name main then the tests for that package should be in main_test. This will help you do black box testing
Writing tests
- Immediate failure - will exit the test function. t.FailNow() , t.Fatal(args ...interface{}) , t.Fatalf(format string, args ..interface{})
- Non-Immediate failure - will continue with the other test functions. t.Fail(), t.Error(args ..interface{}) , t.Errorf(format string, args ..interface{})
Other useful functions All the methods are from golang.org/pkg/testing
- Log and Logf, Helper, Skip, Skipf, SkipNow, Run, Parallel
There are more..
Sample code for a test
func TestAddUser(t *testing.T) {
user := &domain.User{
ID: 7,
FirstName: "",
LastName: "Soy",
Email: "Rabb@email",
}
jsonUser, _ := json.Marshal(user)
request, err := http.NewRequest("POST", "/adduser", bytes.NewBuffer(jsonUser))
if err != nil {
t.Fatal(err)
}
response := httptest.NewRecorder()
helpers.RootHandler(controllers.AddUser).ServeHTTP(response, request)
if response.Result().StatusCode != 200 {
t.Errorf("expected status %v but got %v", 200, response.Result().StatusCode)
}
}
Running Tests
- go test : - Run all tests in the current directory
- go test {pkg1} {pkg2} {pkg3} .. {pkgn} :- test specified packages
- go test ./... :- run tests in current package and its descendants
- go test -v :- verbose output, can be combined with all the other commands
- go test -run {regexp} :- run only tests matching {regexp}
BenchMark Tests
Naming Conventions
- Prefix tests with "BenchMark"
- Accept one parameter *testing.B
Key testing.B Members
- b.N - no of times the tests needs to be executed
- b.StartTimer, b.StopTimer, b.ResetTimer
- b.RunParallel
There are more..
Running Benchmark Tests
- go test -bench - run all tests including benchmark tests
- go test -bench -benchtime 10s - run benchmark tests targeting specified time
Sample Benchmark Test
func BenchmarkAddUser(b *testing.B) {
for i := 0; i < b.N; i++ {
user := &domain.User{
ID: i + 7,
FirstName: "acd",
LastName: "Soy",
Email: "Rabb@email",
}
response, err := makeRequestToAddUser(*user)
if err != nil {
b.Fatal(err)
}
if response.Result().StatusCode != 200 {
b.Errorf("expected status %v but got %v", 200, response.Result().StatusCode)
}
}
}
Profiling Tests
- go test -benchmem : report memory allocation statistics for benchmarks
- go test -trace {trace.out} : record execution trace to {trace.out} for analysis
- go test {type} profile {file} : generate profile of requested type : block, cover, cpu, mem, mutex