• Stars
    star
    112
  • Rank 312,240 (Top 7 %)
  • Language
    Go
  • License
    MIT License
  • Created over 2 years ago
  • Updated 6 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

A tool for formatting Go test results as readable documentation

Go Reference Go Report Card Mentioned in Awesome Go Tests

Writing gopher logo

gotestdox is a command-line tool for formatting Go test results as readable documentation, as recommended in my book The Power of Go: Tests.

Here's how to install it:

go install github.com/bitfield/gotestdox/cmd/gotestdox@latest

In any Go project, run:

gotestdox ./...

Animated demo

What does it do?

gotestdox runs your tests and reports the results, but it formats their names in a special way. It converts test names WrittenInCamelCase into ordinary sentences.

For example, suppose we have some tests named like this:

TestValidIsTrueForValidInputs
TestValidIsFalseForInvalidInputs

We can transform them into readably-spaced sentences that express the desired behaviour, by running gotestdox:

gotestdox

This will run the tests, and print:

 โœ” Valid is true for valid inputs (0.00s)
 โœ” Valid is false for invalid inputs (0.00s)

Why?

I read a blog post by Dan North, which says:

My first โ€œAha!โ€ moment occurred as I was being shown a deceptively simple utility called agiledox, written by my colleague, Chris Stevenson. It takes a JUnit test class and prints out the method names as plain sentences.

The word โ€œtestโ€ is stripped from both the class name and the method names, and the camel-case method name is converted into regular text. Thatโ€™s all it does, but its effect is amazing.

Developers discovered it could do at least some of their documentation for them, so they started to write test methods that were real sentences.
โ€”Dan North, Introducing BDD

How?

The original testdox tool (part of agiledox) was very simple, as Dan describes: it just turned a camel-case JUnit test name like testFailsForDuplicateCustomers into a space-separated sentence like fails for duplicate customers.

And that's what I find neat about it: it's so simple that it hardly seems like it could be of any value, but it is. I've already used the idea to improve a lot of my test names.

There are implementations of testdox for various languages other than Java: for example, PHP, Python, and .NET. I haven't found one for Go, so here it is.

gotestdox reads the JSON output generated by the go test -json command. This is easier than trying to parse Go source code, for example, and also gives us pass/fail information for the tests. It ignores all events except pass/fail events for individual tests (including subtests).

Getting fancy

Some more advanced ways to use gotestdox:

Exit status

If there are any test failures, gotestdox will print the output messages from the offending test and report status 1 on exit.

Colour

gotestdox indicates a passing test with a โœ” (check mark emoji), and a failing test with an x. These are displayed as green and red respectively, using the color library, which automagically detects if it's talking to a colour-capable terminal.

If not (for example, when you redirect output to a file), or if the NO_COLOR environment variable is set to any value, colour output will be disabled.

Test flags and arguments

gotestdox, with no arguments, will run the command go test -json and process its output.

Any arguments you supply will be passed on to go test. For example:

gotestdox -run ParseJSON

will run the command:

go test -json -run ParseJSON

You can supply a list of packages to test, or any other arguments or flags understood by go test. However, gotestdox only prints events about tests (ignoring benchmarks and examples).

Since fuzz test cases are autogenerated and don't tend to have useful names, these are not included in gotestdox output unless they are failing.

Multiple packages

To test all the packages in the current tree, run:

gotestdox ./...

Each package's test results will be prefixed by the fully-qualified name of the package. For example:

github.com/octocat/mymodule/api:
 โœ” NewServer errors on invalid config options (0.00s)
 โœ” NewServer returns a correctly configured server (0.00s)

github.com/octocat/mymodule/util:
 x LeftPad adds the correct number of leading spaces (0.00s)
    util_test.go:133: want "  dummy", got " dummy"

Multi-word function names

There's an ambiguity about test names involving functions whose names contain more than one word. For example, suppose we're testing a function HandleInput, and we write a test like this:

TestHandleInputClosesInputAfterReading

Unless we do something, this will be rendered as:

 โœ” Handle input closes input after reading

To let us give gotestdox a hint about this, there's one extra transformation rule: the first underscore marks the end of the function name. So we can name our test like this:

TestHandleInput_ClosesInputAfterReading

and this becomes:

 โœ” HandleInput closes input after reading

I think this is an acceptable compromise: the gotestdox output is much more readable, while the extra underscore in the test name doesn't seriously interfere with its readability.

The intent is not to perfectly render all sensible test names as sentences, in any case, but to do something useful with them, primarily to encourage developers to write test names that are informative descriptions of the unit's behaviour, and thus (as a side effect) read well when formatted by gotestdox.

In other words, gotestdox is not the thing. It's the thing that gets us to the thing, the end goal being meaningful test names (I like the term literate test names).

Filtering standard input

If you want to run go test -json yourself, for example as part of a shell pipeline, and pipe its output into gotestdox, you can do that too:

go test -json | gotestdox

In this case, any flags or arguments to gotestdox will be ignored, and it won't run the tests; instead, it will act purely as a text filter. However, just as when it runs the tests itself, it will report exit status 1 if there are any test failures.

As a package

See pkg.go.dev/github.com/bitfield/gotestdox for the full documentation on using gotestdox as a package in your own programs.

So what?

Why should you care, then? What's interesting about gotestdox, or any testdox-like tool, I find, is the way its output makes you think about your tests, how you name them, and what they do.

As Dan says in his blog post, turning test names into sentences is a very simple idea, but it has a powerful effect. Test names should be sentences.

Test names should be sentences

I don't know about you, but I've wasted a lot of time and energy over the years trying to choose good names for tests. I didn't really have a way to evaluate whether the name I chose was good or not. Now I do!

In fact, I wrote a whole blog post about it:

It might be interesting to show your gotestdox output to users, customers, or business folks, and see if it makes sense to them. If so, you're on the right lines. And it's quite likely to generate some interesting conversations (โ€œIs that really what it does? But that's not what we asked for!โ€)

It seems that I'm not the only one who finds this idea useful. I hear that gotestdox is already being used in some fairly major Go projects and companies, helping their developers to get more value out of their existing tests, and encouraging them to think in interesting new ways about what tests are really for. How nice!

Links

Gopher image by MariaLetta

More Repositories

1

script

Making it easy to write shell-like scripts in Go
Go
5,457
star
2

ftl-fundamentals

Exercises in the fundamentals of Go, to accompany the book 'For the Love of Go', by John Arundel.
Go
142
star
3

ftl-code

Code listings accompanying the 'For the Love of Go' book
Go
96
star
4

tpg-tools

Code examples from the book 'The Power of Go: Tools'
Go
68
star
5

kg-generics

Exercises and solutions from the book 'Know Go: Generics'
Go
67
star
6

uptimerobot

Client library for UptimeRobot v2 API
Go
57
star
7

gmachine

A set of Go exercises implementing a virtual computer system
Go
56
star
8

puppet-beginners-guide-3

Example code repo for the Puppet 5 Beginner's Guide, 3rd Edition
Shell
44
star
9

puppet-beginners-guide

Play along with the Puppet Beginner's Guide, 2nd edition!
37
star
10

tpg-tools2

Code examples from the book 'The Power of Go: Tools'
Go
26
star
11

tpg-tests

Code examples from the book 'The Power of Go: Tests'
Go
17
star
12

qrand

Quantum randomness source using the ANU hardware QRNG
Go
15
star
13

ftl-data

Exercises to accompany the book 'For the Love of Go: Data', by John Arundel.
Go
15
star
14

terraform-provider-checkly

A Terraform provider for the Checkly monitoring service
Go
15
star
15

control-repo-3

A complete example Puppet infrastructure
Shell
13
star
16

control-repo

A complete example Puppet infrastructure
Puppet
13
star
17

weaver

A simple link checker in Go
Go
10
star
18

kg-generics2

Exercises and solutions from the book 'Know Go: Generics' (2024 edition)
Go
10
star
19

procrastiproxy

A project template for a blocking proxy server in Go.
Go
9
star
20

shellspy

A project template for a shell transcript recorder in Go
Go
9
star
21

weather

A project template for a weather client in Go
Go
9
star
22

morningpost

A project template for a personalised newspaper in Go
Go
8
star
23

know-go

Exercises and solutions from the book 'Know Go'
Go
6
star
24

lander

Crowdsourced lunar lander game written by students, faculty, and friends at the Bitfield Institute of Technology
Go
6
star
25

vim-gitgo

Golang colorscheme for Vim, inspired by GitHub
Vim Script
6
star
26

key

A password strength checking library in Go
Go
6
star
27

checkly

A Go library for use with the Checkly API
Go
6
star
28

cookbook

Shell
5
star
29

eg-crypto

Go code samples and exercises for the book 'Explore Go: Cryptography'
Go
4
star
30

checkd

A Go library for writing programs which collect metrics
Go
4
star
31

tsr-tools

Code examples, exercises, and solutions from the book 'The Secrets of Rust: Tools'
Rust
3
star
32

habit

A project template for a habit tracker in Go
Go
3
star
33

cronrun

A library for parsing crontab strings
Go
3
star
34

grink

A tool to check web links in Markdown files
Rust
3
star
35

shift

A simple shift cipher demonstration in Go
Go
2
star
36

rskey

A simple key-value store in Rust
Rust
2
star
37

adventure

A simple adventure game challenge in Go
Go
2
star
38

checklist

Turn a text file into an interactive checklist
Go
2
star
39

terraform-ci

A single container image for CI-based Terraform testing
Dockerfile
2
star
40

cargo-testdox

Formats Rust test results as readable documentation
Rust
2
star
41

rmachine

A simple RISC CPU for emulation exercises
2
star
42

checkepub

A Go library and CLI tool for validating EPUB files using the HamePub Lint API
Go
2
star
43

linkcheck

A project template for a website link checker in Go.
Go
2
star
44

options

Simple example of functional options in Go
Go
2
star
45

pbg_ntp

Example Puppet module to manage NTP
Puppet
2
star
46

terraform-provider-uptimerobot

A Terraform provider for the Uptime Robot website monitoring service
Go
2
star
47

trm32

A reference emulator in Rust for the TRM32 architecture
Rust
2
star
48

microbit-clock

A digital clock in Rust for the BBC micro:bit
Rust
2
star
49

sicp

Scheme exercises in the 'Structure & Interpretation of Computer Programs' book
Scheme
1
star
50

txtar-c

A tool for creating txtar archives
Go
1
star
51

microbit-beachball

A Rust project for the BBC micro:bit
Rust
1
star
52

tcptest

Go
1
star
53

yijing

A library and command-line tool for consulting the I Ching
Go
1
star
54

embed

Go
1
star
55

edger

Test your Dockerfiles against the latest version of base images
Go
1
star
56

love

Go code samples and exercises for the book 'For the Love of Go'
Go
1
star
57

gcp

A simple client library for accessing Google Cloud resources
Go
1
star
58

Powering-up-with-Puppet

Template and sample code for getting started using Puppet
1
star