DEV Community

Paweł Słomka
Paweł Słomka

Posted on

Testable Examples in Go

This post has been originally published on my blog, MyCodeSmells.com. Check it out for more content!

Writing technical documentation for the application is often more difficult, than creating its code. We, developers, know our craft very well, but when it comes to leaving some signs of how things work, how to use them, etc., we are surprisingly ineffective. On the other hand, when we are about to use some external dependency, we'd love to see examples of how it can be inserted into our code. How do we do that in Go?

When I first heard about testable examples in Go, I didn't think it was such a great idea.

Enhancing documentation

When writing an application in Go, we often do two things: write production code and tests. Those come naturally to anyone and is not specific to this programming language. Sometimes we add another piece, which is benchmarks because it takes very little effort to make them. There is one more thing you could do, but it's the least popular since they are great for the users of the package, not so much of the authors.

You can think of examples as of the tests that check the output that is being printed to the standard output. You can also, obviously, create examples by explicitly calling fmt.Print(..) on a result of some function. This is because the main reason of example functions are to present a snippet of the code and show what is expected to be the output.

Example example

Imagine that we have an exported function that sums two integers:

// sum.go
func Sum(a, b int) int {
    return a + b
}
Enter fullscreen mode Exit fullscreen mode

It might be hard to imagine, but there might be some users that don't know how to use it. To do that, we need to create Example function for Sum, so that it appears in the documentation (via godoc):

// sum_test.go
func ExampleSum() {
    res := Sum(1, 5)
    fmt.Printf(res)
    // Output:
    // 6
}
Enter fullscreen mode Exit fullscreen mode

We can also make small modifications of our examples and identify them by one-word suffix in the example function name:

// sum_test.go
func ExampleSum_negative() {
    Sum(-3, -9)
    //Output:
    // -12
}
Enter fullscreen mode Exit fullscreen mode

Pretty easy, right?

We can also create examples for functions of structs so that they are placed in a correct place in godoc output:

// user.go
type User struct {
    Name string
}

func (u User) Hi() {
    fmt.Printf("Hi, my name is %s!", u.Name)
}
Enter fullscreen mode Exit fullscreen mode

It's important to name the example function using the struct name and the function we want to showcase:

// user_test.go
func ExampleUser_Hi() {
    u := User{"Timmy"}
    u.Hi()
    // Output:
    // Hi, my name is Timmy!
}
Enter fullscreen mode Exit fullscreen mode

Running examples

Once you create your example functions, you have to make sure that the // Output: comment section actually show the output that is returned by the code written above.

Running examples is very simple because they are executed via go test, that is just as any normal tests:

$ go test
--- FAIL: ExampleUser_Hi (0.00s)
got:
Hi, my name is not Timmy!
want:
Hi, my name is Timmy!
FAIL
exit status 1
FAIL    github.com/mycodesmells/golang-examples/misc/examples 0.005s
Enter fullscreen mode Exit fullscreen mode

As you can see, writing examples require very little effort, but they can make your documentation more complete, and make other people more eager to use your packages since they can see how your code works.

The source code of these examples are available on Github, and the documentation is available on GoDoc.

Top comments (0)