Let's Go Testing › Profiling test coverage
Previous · Contents · Next
Chapter 13.8.

Profiling test coverage

A great feature of the go test tool is the metrics and visualizations that it provides for test coverage.

Go ahead and try running the tests in our project using the -cover flag like so:

$ go test -cover ./...
?       snippetbox.alexedwards.net/ui	[no test files]
ok      snippetbox.alexedwards.net/cmd/web	0.013s          coverage: 45.7% of statements
        snippetbox.alexedwards.net/internal/models/mocks    coverage: 0.0% of statements
        snippetbox.alexedwards.net/internal/validator       coverage: 0.0% of statements
        snippetbox.alexedwards.net/internal/assert          coverage: 0.0% of statements
ok      snippetbox.alexedwards.net/internal/models	0.128s  coverage: 11.3% of statements

From the results here we can see that 46.9% of the statements in our cmd/web package are executed during our tests, and for our internal/models package the figure is 11.3%.

We can get a more detailed breakdown of test coverage by method and function by using the -coverprofile flag like so:

$ go test -coverprofile=/tmp/profile.out ./...

This will execute your tests as normal and — if all your tests pass — it will then write a coverage profile to a specific location. In the example above, we’ve instructed it to write the profile to /tmp/profile.out.

You can then view the coverage profile by using the go tool cover command like so:

$ go tool cover -func=/tmp/profile.out
snippetbox.alexedwards.net/cmd/web/handlers.go:15:          home                    0.0%
snippetbox.alexedwards.net/cmd/web/handlers.go:31:          snippetView             92.9%
snippetbox.alexedwards.net/cmd/web/handlers.go:62:          snippetCreate           0.0%
snippetbox.alexedwards.net/cmd/web/handlers.go:88:          snippetCreatePost       0.0%
snippetbox.alexedwards.net/cmd/web/handlers.go:131:         userSignup              100.0%
snippetbox.alexedwards.net/cmd/web/handlers.go:137:         userSignupPost          88.5%
snippetbox.alexedwards.net/cmd/web/handlers.go:192:         userLogin               0.0%
snippetbox.alexedwards.net/cmd/web/handlers.go:198:         userLoginPost           0.0%
snippetbox.alexedwards.net/cmd/web/handlers.go:256:         userLogoutPost          0.0%
snippetbox.alexedwards.net/cmd/web/handlers.go:277:         ping                    100.0%
snippetbox.alexedwards.net/cmd/web/helpers.go:17:           serverError             0.0%
snippetbox.alexedwards.net/cmd/web/helpers.go:30:           clientError             100.0%
snippetbox.alexedwards.net/cmd/web/helpers.go:37:           notFound                100.0%
snippetbox.alexedwards.net/cmd/web/helpers.go:41:           render                  58.3%
snippetbox.alexedwards.net/cmd/web/helpers.go:62:           newTemplateData         100.0%
snippetbox.alexedwards.net/cmd/web/helpers.go:73:           decodePostForm          50.0%
snippetbox.alexedwards.net/cmd/web/helpers.go:102:          isAuthenticated         75.0%
snippetbox.alexedwards.net/cmd/web/main.go:35:              main                    0.0%
snippetbox.alexedwards.net/cmd/web/main.go:100:             openDB                  0.0%
snippetbox.alexedwards.net/cmd/web/middleware.go:11:        commonHeaders           100.0%
snippetbox.alexedwards.net/cmd/web/middleware.go:26:        logRequest              100.0%
snippetbox.alexedwards.net/cmd/web/middleware.go:41:        recoverPanic            66.7%
snippetbox.alexedwards.net/cmd/web/middleware.go:61:        requireAuthentication   16.7%
snippetbox.alexedwards.net/cmd/web/middleware.go:83:        noSurf                  100.0%
snippetbox.alexedwards.net/cmd/web/middleware.go:94:        authenticate            38.5%
snippetbox.alexedwards.net/cmd/web/routes.go:12:            routes                  100.0%
snippetbox.alexedwards.net/cmd/web/templates.go:23:         humanDate               100.0%
snippetbox.alexedwards.net/cmd/web/templates.go:40:         newTemplateCache        83.3%
snippetbox.alexedwards.net/internal/models/snippets.go:31:  Insert                  0.0%
snippetbox.alexedwards.net/internal/models/snippets.go:60:  Get                     0.0%
snippetbox.alexedwards.net/internal/models/snippets.go:97:  Latest                  0.0%
snippetbox.alexedwards.net/internal/models/users.go:34:     Insert                  0.0%
snippetbox.alexedwards.net/internal/models/users.go:66:     Authenticate            0.0%
snippetbox.alexedwards.net/internal/models/users.go:98:     Exists                  100.0%
total:                                                      (statements)            38.1%

An alternative and more visual way to view the coverage profile is to use the -html flag instead of -func.

$ go tool cover -html=/tmp/profile.out

This will open a browser window containing a navigable and highlighted representation of your code, similar to this:

13.08-01.png

The statements which get executed during your tests are colored green, and those that are not executed are colored red. This makes it easy to see exactly what code is currently covered by your tests (unless you have red-green color blindness).

You can take this a step further and use the -covermode=count option when running go test like so:

$ go test -covermode=count -coverprofile=/tmp/profile.out ./...
$ go tool cover -html=/tmp/profile.out

Instead of just highlighting the statements in green and red, using -covermode=count makes the coverage profile record the exact number of times that each statement is executed during the tests.

When viewed in the browser, statements which are executed more frequently are then shown in a more saturated shade of green, similar to this:

13.08-02.png