Table of Content
Introduction
Go has incredible tooling out of the box. It has tools for testing, benchmarking, profiling etc. I want to discuss an interesting one that impressed me: go test coverage and the different visualization options.
Go Tests
To help us understand these concepts, we will be writing some functions to do basic calculations.
- Let's first write a function that adds two numbers
func Add(num1 int, num2 int) int {
return num1 + num2
}
- Let's write some tests for it
import "testing"
func TestAddition(t *testing.T) {
got := Add(1, 3)
want := 4
if got != want {
t.Errorf("wanted %d got %d", want, got)
}
}
- Let's run our tests to see if everything is ok
go test ./...
ok github.com/quamejnr/go-cover 0.687s
Everything looks good.
We can also see how much of our code written is covered by tests and this is where the excitement begins.
Go Tests Coverage
To see the test coverage, we can add a -cover
flag to our go test
command.
go test ./... -cover
ok github.com/quamejnr/go-cover (cached) coverage: 100.0% of statements
Currently we are 100% covered as we have written tests for all our code.
Now let's add a division function and see what happens.
func Div(num int, denom int) int {
if denom == 0 {
panic("invalid division error")
}
return num / denom
}
We can rerun our test coverage command and see our response.
go test ./... -cover
ok github.com/quamejnr/go-cover (cached) coverage: 50.0% of statements
Now we've covered only 50% of our coverage as we are yet to write tests for our division function.
For a simple case like this, it's obvious what we need to test but in a larger codebase it's not so apparent and this is where coverage can be very powerful.
Go gives us tools to visualize where exactly in our code have not been tested.
We can do this by passing in some flags to our go test command: go test -coverprofile=c.out
. coverprofile
generates a coverage profile with the value being the name of the output file, in this case c.out
.
Once you have the profile c.out
, you can examine it to know more about your code coverage using the go's tool command.
We can check it out on our terminal using the command
go tool cover -func=c.out
github.com/quamejnr/go-cover/main.go:3: Add 100.0%
github.com/quamejnr/go-cover/main.go:7: Div 0.0%
total: (statements) 50.0%
This shows our Div
function is yet to have any test coverage so let's add test coverage to our Div
function.
func TestDivison(t *testing.T) {
t.Run("Test division", func(t *testing.T) {
got := Div(4, 2)
want := 2
if got != want {
t.Errorf("wanted %d got %d", want, got)
}
})
}
Now we should have covered everything. Let's run our coverage again and see
go test ./... -cover
ok github.com/quamejnr/go-cover 0.213s coverage: 75.0% of statements
It says we have covered only 75% of our test coverage.
And if we generate our cover profile again and inspect it.
go test ./... -coverprofile=c.out
go tool cover -func=c.out
github.com/quamejnr/go-cover/main.go:3: Add 100.0%
github.com/quamejnr/go-cover/main.go:7: Div 66.7%
total: (statements) 75.0%
We can see we have covered only 66.7%
of our Div
code but this doesn't give us much info on what we're missing out.
This is where another useful visualization tool of the coverprofile comes in.
Go gives us the ability to look at our code in our browser to see which parts are yet to be tested. All we need to do is change our -func
flag to -html
flag.
go tool cover -html=c.out
This screenshot shows us that we're yet to test our path when denom
is 0.
Let's update our TestDivison
function to handle that.
func TestDivison(t *testing.T) {
t.Run("Test division", func(t *testing.T) {
got := Div(4, 2)
want := 2
if got != want {
t.Errorf("wanted %d got %d", want, got)
}
})
t.Run("Test division with 0", func(t *testing.T) {
defer func() {
if r := recover(); r == nil {
t.Errorf("zero divsion did not panic")
}
}()
Div(4, 0)
})
}
Now if we run our go test coverage command, we should have 100% coverage.
go test ./... -cover
ok github.com/quamejnr/go-cover 0.649s coverage: 100.0% of statements
Conclusion
In this article, we examined how we can use go's coverage tools to help us with our testing coverage
We learnt how to;
- create coverage profiles
- examine them in our terminal
- visualize them in our browsers. All code can be found here https://github.com/quamejnr/go-cover
Top comments (0)