Testable Examples in Go With Example Functions and Output
Write Go example functions that are documentation and tests at once: naming rules, the Output and Unordered output comments, examples without output.

An example in Go documentation is usually code that someone wrote once and never ran again. The testing package fixes that with a convention: a function named Example something, in a test file, whose printed output is checked against a comment. The example is then compiled with the package, run with the tests, and displayed on the package page. If the API changes and the example stops compiling or stops printing the same thing, go test fails. Documentation that fails the build does not rot.
Tested with Go 1.25.6, macOS on Apple Silicon (arm64)
This article covers the naming rules, the two output comments, the cases where an example does not run, and what a failure looks like, on Go 1.25.6.
The code and its examples
package shout
import (
"sort"
"strings"
)
// Upper returns s in upper case with an exclamation mark.
func Upper(s string) string { return strings.ToUpper(s) + "!" }
// Words returns the distinct words in s, in no particular order.
func Words(s string) map[string]int {
m := map[string]int{}
for _, w := range strings.Fields(s) {
m[strings.ToLower(w)]++
}
return m
}
// Sorted returns the keys of m in order.
func Sorted(m map[string]int) []string {
keys := make([]string, 0, len(m))
for k := range m {
keys = append(keys, k)
}
sort.Strings(keys)
return keys
}package shout_test
import (
"fmt"
"testing"
shout "example.test/lab"
)
func ExampleUpper() {
fmt.Println(shout.Upper("hello"))
// Output: HELLO!
}
func ExampleWords() {
for _, w := range shout.Sorted(shout.Words("the cat and The dog")) {
fmt.Println(w)
}
// Output:
// and
// cat
// dog
// the
}
func ExampleWords_unordered() {
for w, n := range shout.Words("b a b") {
fmt.Println(w, n)
}
// Unordered output:
// a 1
// b 2
}
// No Output comment: compiled, shown in docs, never run.
func ExampleUpper_notRun() {
fmt.Println(shout.Upper("this is not executed"))
}
func ExampleUpper_wrong() {
fmt.Println(shout.Upper("go"))
// Output: GO
}
func TestPlaceholder(t *testing.T) {}echo "# examples run with the tests"
go test -count=1 -v -run 'Example' . 2>&1 | grep -vE '^(=== RUN|PASS)' | sed -E 's/ \([0-9.]+s\)//; s/\t[0-9.]+s$//'
echo
echo "# list shows examples too"
go test -list . | head -8# examples run with the tests
--- PASS: ExampleUpper
--- PASS: ExampleWords
--- PASS: ExampleWords_unordered
--- FAIL: ExampleUpper_wrong
got:
GO!
want:
GO
FAIL
FAIL example.test/lab
FAIL
# list shows examples too
TestPlaceholder
ExampleUpper
ExampleWords
ExampleWords_unordered
ExampleUpper_wrong
ok example.test/lab 0.163sThe examples live in package shout_test, the external test package, and import the package like a user would. That is the usual choice: an example shows how a caller uses the API, so it should only use what a caller can. They could be in package shout too, but then they might use unexported names that a reader cannot. See the article on external test packages for the trade-offs.
Naming decides where the example appears
The name tells go doc and pkg.go.dev what the example documents.
| Name | Attached to |
|---|---|
Example | The package as a whole |
ExampleUpper | The function Upper |
ExampleStack | The type Stack |
ExampleStack_Push | The method Push of Stack |
ExampleUpper_notRun | A second example of Upper, with the suffix notRun |
A suffix, after an underscore, must start with a lower case letter. This is how one function gets several examples: ExampleWords and ExampleWords_unordered. The suffix becomes the example's title on the documentation page. A name that does not match any identifier in the package is reported by go vet, which catches the typo that would silently orphan an example.
The output comment
An example is run when its body ends with a comment that starts with Output:. The test runner captures what the function writes to standard output, trims leading and trailing whitespace from both the output and the comment, and compares them. For one line the comment can sit on one line, as in // Output: HELLO!. For several lines, put the first on the next line and indent the rest the same way:
// Output:
// and
// cat
// dog
// theExampleWords shows why examples are good for functions that return maps. The map has no order, so the example sorts the keys with Sorted before printing, and the output is stable. An example that prints a map directly with fmt.Println is stable too, because fmt sorts map keys when printing, but one that ranges over a map is not.
Unordered output
ExampleWords_unordered ranges over the map on purpose. Go randomises map iteration, so no single order of lines is right. The comment // Unordered output: tells the runner to sort both the output and the expected lines before comparing. It passed in the recorded run, with a 1 and b 2 in either order. Use it for concurrent code whose goroutines print in any order, and for maps, and not as a general way to avoid fixing the order of something that has one. It compares lines as a multiset, so a missing or extra line still fails.
What a failure looks like
ExampleUpper_wrong expects GO and the function prints GO!. The test fails with a got: block holding GO! and a want: block holding GO. The format makes trailing whitespace and a missing newline hard to see, so if the two look identical, suspect whitespace in the middle of a line, which is not trimmed. The example's name is in the --- FAIL header, and you fix it by correcting either the code or the comment. Treat the comment as the specification of what a reader should see.
Examples that do not run
ExampleUpper_notRun has no output comment. The compiler still checks that it builds, go vet still checks the names, and the documentation still shows it, but go test does not execute it. That is right for examples that cannot be deterministic or must not run in a test: they call the network, print a time, need a credentials file, or start a server. They become compile-checked documentation. The listing in the lab shows it among the names, so -list reports it even though -run would not execute it.
Do not add // Output: and fake the result to make an example run. If it cannot be checked, leave the comment out and say so in the prose around it. Also avoid examples that print from a goroutine and return before the output appears; the runner reads standard output when the function returns.
Whole file examples
An example can be larger than a function. If a test file contains exactly one example function, no test or benchmark functions, and at least one other package-level declaration, such as a type or a helper, the documentation shows the whole file as the example. That is how you present a complete program with its own types around the call. The lab file has a test in it, so its examples are shown as single functions; the exact conditions are in the testing package documentation on examples.
Where examples fit
Examples are not a replacement for unit tests. They show the happy path in a form a reader can learn from, and they check only that. Put edge cases, errors and boundaries in table tests, and use examples for the three or four calls that explain the package: how to construct it, how to call it, what comes back. Because they are documentation first, keep them short and free of test machinery, with no t, no helpers and no setup that a user would not write.
The practice scales: a package with an example for every exported function has an up-to-date user guide that costs nothing to maintain. The documentation-as-tests note covers the package-level case, and the testing hub places it with the other test kinds. The conventions are written out in the Go blog's article on testable examples.


