Gotcha: testable examples in Go need an output
comment
One thing I really like about building libraries in Go is that you can create testable examples as a first-class citizen of the testing framework. This allows writing example code in the repository in a way that can make sure that expected use cases are always valid and do not break, but because it's annotated as an example test case, it then gets surfaced in documentation as examples.
For instance, we can see the below code which shows how to parse some HTTP Accept headers and the resulting response when printed out to stdout
:
// source via https://gitlab.com/jamietanna/content-negotiation-go/blob/299506d7f0487fefb9e2f1f828c7c306cbe211f9/acceptheader_test.go#L38-47
func ExampleParseAcceptHeaders() {
parsed := contentnegotiation.ParseAcceptHeaders("text/html", "application/json")
for _, mt := range parsed {
fmt.Println(mt.String())
}
// output:
// text/html
// application/json
}
One thing you'll notice is that we've got this output
line, which checks what output is returned from the example.
This is the crux of this post - if you don't have this output:
line, your test will not be executed, and although it'll be compiled, it will never execute in your tests.
I found this when working through a few internal libraries, and noticed that by changing functionality in the tests - that were designed to make them fail - I saw no errors.
The solution is to make sure that you're always asserting on the output:
of an example test, but trying to remember that all the time is difficult, so I've raised this upstream at golangci-lint
as something we may want to surface in linting. And lo and behold, someone has already prepared a check for it - Open Source is great!
An additional gotcha is that you need to make sure that your comments have a newline between them - for instance the following won't work:
func ExampleParseAcceptHeaders() {
parsed := contentnegotiation.ParseAcceptHeaders("text/html", "application/json")
for _, mt := range parsed {
fmt.Println(mt.String())
}
// this won't actually work, because the output is inside another command - this needs a newline breaking the comments
// output:
// text/html
// application/json
}